查找类型,其is_constructible成立 [英] finding type, for which is_constructible holds

查看:31
本文介绍了查找类型,其is_constructible成立的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用模板,并试图实现以下帮助程序。

I was playing around with templates and was trying to implement following helper.

first_constructible<Types..., Args...>::type

这将返回 Types ,可从 Args ... 构造。第一个问题显然是在 struct 中有两个参数包,因此我将用法更改为

which would return first type of Types which is constructible from Args.... First problem obviously is having two parameter packs in struct, so I changed usage to

first_constructible<std::tuple<Types...>, Args...>::type

我已经通过将元组类型分为第一和其余部分来实现它,使用 std :: is_constructible 进行了检查,并在必要时进行了递归。

I've implemented it by splitting tuple types as first and rest, checked using std::is_constructible and recursed if neccessary.

template<typename T>
struct pop_front_tuple
{
    template<typename U, typename... Us>
    static std::tuple<Us...> impl(std::tuple<U, Us...>);

    using type = decltype(impl(std::declval<T>())); // std::tuple with removed first type
};

template<typename Tuple, typename... Args>
struct first_constructible
{
    using first_type = decltype(std::get<0>(std::declval<Tuple>()));

    using type = typename std::conditional
    <
        std::is_constructible<first_type, Args...>::value,
        first_type,
        typename first_constructible<typename pop_front_tuple<Tuple>::type, Args...>::type
    >::type;
};

// end of recursion
template<typename... Args>
struct first_constructible<std::tuple<>, Args...>
{
    using type = void;
};

但由于某种原因它不起作用。即

but it for some reason does not work. I.e

first_constructible<std::tuple<std::string, int>, std::string>::type a = ""; // works, a is std::string
first_constructible<std::tuple<std::string, int>>::type a = ""; // fails, error: variable or field 'a' declared void
first_constructible<std::tuple<std::string, int>, std::string::size_type, std::string::value_type> // fails, same error

我不知道我的错误在哪里。 std :: is_constructible< std :: string> :: value std :: is_constructible< std :: string,std :: string :: size_type ,std :: string :: value_type> :: value 为真。

I don't know where my mistake is. std::is_constructible<std::string>::value and std::is_constructible<std::string, std::string::size_type, std::string::value_type>::value are true.

Coliru链接

推荐答案

首先,进行一些元编程玩具:

First, some metaprogramming toys:

template<class Tag>
using type_t = typename Tag::type;
template<class T> struct tag_t{using type=T; constexpr tag_t(){}};
template<class T> constexpr tag_t<T> tag{};

template<class...Tuples>
using cat_tuples = decltype(std::tuple_cat( std::declval<Tuples>()... ));

template<template<class...>class Z, class Tuple, class=void>
struct filter;
template<template<class...>class Z, class Tuple>
using filter_t = type_t<filter<Z,Tuple>>;

template<template<class...>class Z>
struct filter<Z, std::tuple<>,void>:tag_t<std::tuple<>>{};
template<template<class...>class Z, class T0, class...Ts>
struct filter<Z, std::tuple<T0, Ts...>, std::enable_if_t<Z<T0>::value>>:
    tag_t<
        cat_tuples<
            std::tuple<T0>,
            filter_t<Z, std::tuple<Ts...>>
        >
    >
{};
template<template<class...>class Z, class T0, class...Ts>
struct filter<Z, std::tuple<T0, Ts...>, std::enable_if_t<!Z<T0>::value>>:
    filter<Z, std::tuple<Ts...>>
{};

现在我们解决您的问题:

Now we solve your problem:

template<class...Args>
struct is_constructible_test {
    template<class T>
    using result=std::is_constructible<T,Args...>;
};

template<class Tuple, class...Args>
using all_constructible_t = filter_t<is_constructible_test<Args...>::template result, Tuple>;

template<class Tuple, class...Args>
using first_constructible = std::tuple_element_t<0, all_constructible_t<Tuple,Args...>>;

测试代码:

struct bob {
    bob( int, int, int ) {}
};
template<std::size_t>
struct alice {
    alice(int) {}
};

int main() {
    using is_alice = first_constructible<std::tuple<std::string, bob, alice<1>, alice<2>, int>, int>;
    static_assert( std::is_same<is_alice, alice<1>>::value, "works" );
}

实时示例

C ++ 14,但仅用于 _t 别名。将 std :: foo_t< blah> 替换为 typename std :: foo< blah> :: type

C++14, but just for _t aliases. replace std::foo_t<blah> with typename std::foo<blah>::type.

我所做的就是找到每个可构造类型,然后抓取第一个。过滤器是我经常遇到的一个简单概念,它比编写通过测试的先获取要容易,因为过滤器随后无条件获取先决条件在逻辑上是相同的(如果价格更高)。

What I did was find every constructible type, then grabbed the first one. Filter is a simple concept I had lying around, and it was easier than writing "get first that passes test", as filter followed by get first unconditional is logically the same (if a bit more expensive).

您可以将上面的 filter 修改为短路,然后返回,而不是在测试通过时用尾巴代替:

You could modify filter above to "short out" and return instead of concatinating with tail when the test passes:

template<template<class...>class Z, class Tuple, class=void>
struct search;
template<template<class...>class Z, class Tuple>
using search_t = type_t<search<Z,Tuple>>;

template<template<class...>class Z>
struct search<Z, std::tuple<>,void>{};
template<template<class...>class Z, class T0, class...Ts>
struct search<Z, std::tuple<T0, Ts...>, std::enable_if_t<Z<T0>::value>>:
    tag_t<T0>
{};
template<template<class...>class Z, class T0, class...Ts>
struct search<Z, std::tuple<T0, Ts...>, std::enable_if_t<!Z<T0>::value>>:
    search<Z, std::tuple<Ts...>>
{};

并将 first_constructible 模板替换为:

template<class Tuple, class...Args>
using first_constructible = search_t<is_constructible_test<Args...>::template result, Tuple>;

实时示例2

我可能会像使用与Tuples交互而不是专门化的实用程序函数那样使用就是优势。

I could probably use utility functions like you did that interacts with Tuples rather than specializing, and there would be advantages.

我发现您遇到的一个问题是 get< 返回一个引用,而不是一个值。 std :: tuple_element_t 可能是一个更好的计划。

One issue I see with yours is that get<> returns a reference, not a value. std::tuple_element_t might be a better plan.

这篇关于查找类型,其is_constructible成立的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆