首先,一些元编程玩具:
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...>>
{};
现在我们解决您的问题:
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>
with typename std::foo<blah>::type
.
我所做的是找到every可构造类型,然后抓住第一个。过滤器是我一直以来的一个简单概念,它比编写“首先通过测试”更容易,因为过滤器后跟“首先无条件”在逻辑上是相同的(如果更昂贵的话)。
你可以修改filter
当测试通过时,上面的“短路”并返回而不是与 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...>>
{};
并替换first_constructible
模板包含:
template<class Tuple, class...Args>
using first_constructible = search_t<is_constructible_test<Args...>::template result, Tuple>;
实例2.
我可能可以像您一样使用实用函数来与元组交互而不是专门化,并且会有优势。
我看到你的一个问题是get<>
返回一个引用,而不是一个值。std::tuple_element_t
可能是一个更好的计划。