编译参数类型

时间:2018-01-08 07:58:30

标签: c++ templates c++17

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

struct test_class
{
    void test( int a );
    void test( float b );
};

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

2 个答案:

答案 0 :(得分:2)

如果你能够以相当于(我知道它丑陋的方式)装饰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反馈:)

答案 1 :(得分:1)

IIUC,您希望将类的某些检查应用于类型列表并累积(?)结果。如果是这样,您可以使用代码,如下所示:

#include <boost/mpl/list.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/front.hpp>
#include <type_traits>

template <typename ClassT, typename ParamT>
struct check : public std::true_type
{
};

// template <typename ClassT>
// struct check<ClassT, double> : public std::false_type
// {
// };

template <typename ClassT, typename ParamList, bool list_empty>
struct apply;

template <typename ClassT, typename ParamList>
struct apply <ClassT, ParamList, true> : public std::true_type{};

template <typename ClassT, typename ParamList>
struct apply <ClassT, ParamList, false> :
public std::integral_constant<
    bool,
    apply<
            ClassT,
            typename boost::mpl::pop_front<ParamList>::type,
            boost::mpl::empty<typename boost::mpl::pop_front<ParamList>::type>::value
        >::value && check<ClassT, typename boost::mpl::front<ParamList>::type>::value>
{
};

class Test
{
};

#include <iostream>
int main(int , char ** ) {

    std::cout << std::boolalpha << apply<Test, boost::mpl::list<int, float, double>, false>::value << std::endl;
    return 0;
}

假设check是您的自定义检查,其中包含std::true_typestd::false_type。如果您取消注释double的专精,则结果将从true更改为false