如何检测一个类型是否是泛型类型列表中的一个
How to detect if a type is one of a list of generic types
如果我有
template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
如果某些候选类型 X
是其中之一,最紧凑的测试方法是什么?我正在寻找类似
的内容
boost::enable_if< is_instantiation_of_any<X,A,B,C,D> >
但是A、B、C和D是模板,所以我不确定如何构造上面的内容。
不确定是否存在 std::is_instantiation_of
,但如果所有模板都具有相同数量的参数,则实现起来很简单(如果不存在则更复杂)。要检查一个类型是否是任何给定模板的实例化,您只需要折叠它(需要 C++17):
#include<iostream>
#include<type_traits>
template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
template <typename T,template<typename> typename X>
struct is_instantiation_of : std::false_type {};
template <typename A,template<typename> typename X>
struct is_instantiation_of<X<A>,X> : std::true_type {};
template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
static const bool value = ( ... || is_instantiation_of<T,X>::value);
};
int main(){
std::cout << is_instantiation_of< A<int>, A>::value;
std::cout << is_instantiation_of< A<double>, B>::value;
std::cout << is_instantiation_of_any< A<int>,A,B>::value;
}
101
要获得符合 C++11 的解决方案,我们可以使用 :
之一的巧妙技巧
template <bool ... Bs>
using meta_bool_and = std::is_same<std::integer_sequence<bool, true, Bs...>,
std::integer_sequence<bool, Bs..., true>>;
很聪明,true,a,b,c
和a,b,c,true
只有在a
,b
和c
都是true
时才相同。 std::integer_sequence
是 C++14,但我们在这里只需要一个将 bool 作为其定义的一部分的类型:
namespace my {
template <typename T,T ...t>
struct integer_sequence {};
}
使用它我们可以将上面的代码重写为:
template <bool ... Bs>
using my_all = std::is_same<my::integer_sequence<bool, true, Bs...>,
my::integer_sequence<bool, Bs..., true>>;
因为 "ANY(a,b,c,d,...)"
只是 "! ALL( !a, !b, !c, !d,...)"
我们可以使用:
template <bool ... Bs>
struct my_any { static constexpr bool value = ! my_all< ! Bs...>::value; };
以 C++11 友好的方式编写 is_instantiation_of_any
:
template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
static const bool value = my_any< is_instantiation_of<T,X>::value ...>::value;
};
使用 C++17(或 C++14,如果您根据评论进行编辑),您可以使用 boost::hana::any_of
作为助手:
#include <iostream>
#include <boost/hana/any_of.hpp>
#include <boost/hana/tuple.hpp>
#include <type_traits>
namespace hana = boost::hana;
template <typename T> struct A {};
template <typename T> struct B {};
template <typename T> struct C {};
template <typename T> struct D {};
template <typename T> struct N {};
template<typename T>
bool fun(T) { // overload for non-templated arguments (templated arguments
return false; // are a better match for the overload below)
}
template<typename T, template<typename> typename X>
bool fun(X<T>) { // overload for templated arguments
auto constexpr pred = [](auto x){ // remove constexpr for < c++17
return std::is_same_v<decltype(x), X<T>>;
// return std::is_same<decltype(x), X<T>>::value; // for < c++17
};
return hana::any_of(hana::tuple<A<T>, B<T>, C<T>, D<T>>{}, pred);
};
int main() {
A<int> a{};
N<int> b{};
int x = 3; fun(x);
std::cout << fun(a) << fun(b) << fun(x) << std::endl; // prints 100
}
可能您想在将内容传递给 std::is_same_v
之前使用 std::decay_t
。
如果我有
template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
如果某些候选类型 X
是其中之一,最紧凑的测试方法是什么?我正在寻找类似
boost::enable_if< is_instantiation_of_any<X,A,B,C,D> >
但是A、B、C和D是模板,所以我不确定如何构造上面的内容。
不确定是否存在 std::is_instantiation_of
,但如果所有模板都具有相同数量的参数,则实现起来很简单(如果不存在则更复杂)。要检查一个类型是否是任何给定模板的实例化,您只需要折叠它(需要 C++17):
#include<iostream>
#include<type_traits>
template <typename T> struct A;
template <typename T> struct B;
template <typename T> struct C;
template <typename T> struct D;
template <typename T,template<typename> typename X>
struct is_instantiation_of : std::false_type {};
template <typename A,template<typename> typename X>
struct is_instantiation_of<X<A>,X> : std::true_type {};
template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
static const bool value = ( ... || is_instantiation_of<T,X>::value);
};
int main(){
std::cout << is_instantiation_of< A<int>, A>::value;
std::cout << is_instantiation_of< A<double>, B>::value;
std::cout << is_instantiation_of_any< A<int>,A,B>::value;
}
101
要获得符合 C++11 的解决方案,我们可以使用
template <bool ... Bs> using meta_bool_and = std::is_same<std::integer_sequence<bool, true, Bs...>, std::integer_sequence<bool, Bs..., true>>;
很聪明,true,a,b,c
和a,b,c,true
只有在a
,b
和c
都是true
时才相同。 std::integer_sequence
是 C++14,但我们在这里只需要一个将 bool 作为其定义的一部分的类型:
namespace my {
template <typename T,T ...t>
struct integer_sequence {};
}
使用它我们可以将上面的代码重写为:
template <bool ... Bs>
using my_all = std::is_same<my::integer_sequence<bool, true, Bs...>,
my::integer_sequence<bool, Bs..., true>>;
因为 "ANY(a,b,c,d,...)"
只是 "! ALL( !a, !b, !c, !d,...)"
我们可以使用:
template <bool ... Bs>
struct my_any { static constexpr bool value = ! my_all< ! Bs...>::value; };
以 C++11 友好的方式编写 is_instantiation_of_any
:
template <typename T,template<typename> typename...X>
struct is_instantiation_of_any {
static const bool value = my_any< is_instantiation_of<T,X>::value ...>::value;
};
使用 C++17(或 C++14,如果您根据评论进行编辑),您可以使用 boost::hana::any_of
作为助手:
#include <iostream>
#include <boost/hana/any_of.hpp>
#include <boost/hana/tuple.hpp>
#include <type_traits>
namespace hana = boost::hana;
template <typename T> struct A {};
template <typename T> struct B {};
template <typename T> struct C {};
template <typename T> struct D {};
template <typename T> struct N {};
template<typename T>
bool fun(T) { // overload for non-templated arguments (templated arguments
return false; // are a better match for the overload below)
}
template<typename T, template<typename> typename X>
bool fun(X<T>) { // overload for templated arguments
auto constexpr pred = [](auto x){ // remove constexpr for < c++17
return std::is_same_v<decltype(x), X<T>>;
// return std::is_same<decltype(x), X<T>>::value; // for < c++17
};
return hana::any_of(hana::tuple<A<T>, B<T>, C<T>, D<T>>{}, pred);
};
int main() {
A<int> a{};
N<int> b{};
int x = 3; fun(x);
std::cout << fun(a) << fun(b) << fun(x) << std::endl; // prints 100
}
可能您想在将内容传递给 std::is_same_v
之前使用 std::decay_t
。