我确实知道几种检测给定类是否具有带有指定签名的函数的方法。我想在编译时推断出签名。考虑:
struct test_class
{
void test( int a );
void test( float b );
};
我可以使用decltype和SFINAE通过
has_test<test_class,int>();
这样的简单语法来检测指定的test()的存在。但是我想要的是类似test_types<test_class>::types -> mpl::list< int, float >
的东西。任何人都有理智的想法该怎么做?要求是无法准备可检测类型的列表(因此它将检测任何test( T )
,而不仅仅是我们“注册”的那些。 最佳答案
如果您可以负担得起装饰test()
重载的等效方式(我知道这很丑陋,也许您可以提出一些更漂亮的东西):
struct test_class
{
param<int> test( int a, param_id<0> ={} );
param<float> test( float a, param_id<1> ={} );
};
那么类似的东西应该可以工作(godbolt conformance view):
template<typename T> struct param{ using type = T; };
template<int I> struct param_id{};
template<typename... T> struct type_list{};
struct anything{ template<typename T> operator T&&(); };
template<int I>
struct matcher
{
template<typename T, typename E = std::enable_if_t<std::is_same<T,param_id<I>>::value> >
operator T();
};
template<typename T,int I,typename = std::void_t<>,typename... Ts>
struct test_types_impl{ using type = type_list<Ts...>; };
template<typename T,int I,typename... Ts>
struct test_types_impl<T,I,std::void_t<decltype(std::declval<T>().test( anything{}, matcher<I>{} ))>,Ts...>:
test_types_impl<T,I+1,void,Ts...,typename decltype(std::declval<T>().test( anything{}, matcher<I>{} ))::type>
{
};
template<typename T>
struct test_types{ using type = typename test_types_impl<T,0>::type; };
struct test_class
{
param<int> test( int a, param_id<0> ={} );
param<float> test( float a, param_id<1> ={} );
};
static_assert( std::is_same_v<test_types<test_class>::type, type_list<int,float>> );
上面至少需要可移动构造的参数类型和C++ 17(但我认为它也可以在C++ 11中工作,并且可以使用任何类型)。
如果您设法对一组允许的参数类型进行总排序,则可以省略
param_id
。也许,我们甚至可以以某种方式忽略param<T>
,但不确定(等待OP反馈:)关于c++ - 参数类型的编译时类型检测,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48146255/