找到类型,is_constructible成立

Zer*_*ges 3 c++ templates template-meta-programming c++11

我正在玩模板,并试图实现以下帮助.

first_constructible<Types..., Args...>::type
Run Code Online (Sandbox Code Playgroud)

它将返回第一种Types可构造的类型Args....第一个问题显然是有两个参数包struct,所以我改用了

first_constructible<std::tuple<Types...>, Args...>::type
Run Code Online (Sandbox Code Playgroud)

我已经通过拆分元组类型作为第一个和休息来实现它,检查使用std::is_constructible并在必要时递归.

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;
};
Run Code Online (Sandbox Code Playgroud)

但它出于某种原因不起作用.即

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
Run Code Online (Sandbox Code Playgroud)

我不知道我的错误在哪里.std::is_constructible<std::string>::value并且std::is_constructible<std::string, std::string::size_type, std::string::value_type>::value是真的.

Coliru链接

Yak*_*ont 5

首先,一些元编程玩具:

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...>>
{};
Run Code Online (Sandbox Code Playgroud)

现在我们解决您的问题:

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...>>;
Run Code Online (Sandbox Code Playgroud)

测试代码:

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" );
}
Run Code Online (Sandbox Code Playgroud)

实例.

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

我所做的是找到每一个可构造的类型,然后抓住第一个.过滤器是我所处理的一个简单概念,它比写"先通过测试"更容易,因为过滤器后跟第一个无条件是逻辑上相同(如果有点贵).

你可以修改filter上面的"short out"并返回,而不是在测试通过时用tail结合:

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...>>
{};
Run Code Online (Sandbox Code Playgroud)

并将first_constructible模板替换为:

template<class Tuple, class...Args>
using first_constructible = search_t<is_constructible_test<Args...>::template result, Tuple>;
Run Code Online (Sandbox Code Playgroud)

实例2.

我可能会使用像你那样与元组交互而不是专门化的实用函数,并且会有优势.


我看到你的一个问题是get<>返回引用,而不是值. std::tuple_element_t可能是一个更好的计划.