查找类型,其is_constructible成立 [英] finding type, for which is_constructible holds
问题描述
我正在使用模板,并试图实现以下帮助程序。
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.
推荐答案
首先,进行一些元编程玩具:
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屋!