编译参数类型的时间类型检测

Kor*_*icz 5 c++ templates c++17

我知道几种方法来检测给定的类是否具有指定签名的函数.我想要的是在编译时推断出签名.考虑:

struct test_class
{
    void test( int a );
    void test( float b );
};
Run Code Online (Sandbox Code Playgroud)

我可以使用decltype和SFINAE来检测指定test()的存在,使用简单的语法has_test<test_class,int>();.然而,我想要的是类似的东西test_types<test_class>::types -> mpl::list< int, float >.任何人都有一个明智的想法如何做到这一点?要求是无法准备可检测类型的列表(因此它将检测任何类型test( T ),而不仅仅是我们"注册"的类型.

Mas*_*nes 2

如果你能test()负担得起以相当于(我知道这很丑,也许你可以拿出更漂亮的东西)的方式装饰重载:

struct test_class
{
    param<int> test( int a, param_id<0> ={} );
    param<float> test( float a, param_id<1> ={} );
};
Run Code Online (Sandbox Code Playgroud)

那么这样的事情应该可以工作(godbolt一致性视图):

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

上面至少需要可移动构造的参数类型和 C++17(但我认为它也可以在 C++11 中工作,并且可以使用任何类型)。

param_id如果您设法获得允许的参数类型集的总排序,则可以省略。也许,我们甚至可以以param<T>某种方式省略,但不确定(等待OP对此的反馈:))