C ++:从struct中的静态函数提取参数类型

时间:2018-11-29 17:20:05

标签: c++ templates c++17 template-meta-programming template-deduction

说我有这样的东西:

template<typename T, typename R>
struct MyStruct {
    static R myfunc(T);
};

struct MyStructInst: S<int, double> {
    static double myfunc(int i) { return i; }
};

然后,我有一个模板,它使用M,我将假定该类型具有带有一个参数的静态myfunc函数(例如MyStructInst)。我想提取参数类型和结果类型myfunc

template<typename M,
    typename ParamType = ???,
    typename ResultType = decltype(declval(M::myfunc))> // I think this works?
struct MyStruct2 {
    ...
};

获得ParamType的最简单方法是什么?

1 个答案:

答案 0 :(得分:1)

template <typename R, typename A0, typename ... As>
constexpr A0 firstArg (R(*)(A0, As...));

template <typename M,
          typename PT = decltype(firstArg(&M::myfunc)),
          typename RT = decltype(M::myfunc(std::declval<PT>()))>
struct MyStruct2 
 { };

我的意思是...如果您声明了一个接受函数类型的函数(无需记住,因为它仅在decltype()中使用,因此只有返回的类型才重要)。指向 static 方法的指针类似于指向传统函数的指针),该指针接收一个或多个参数并返回第一个参数的类型

template <typename R, typename A0, typename ... As>
constexpr A0 firstArg (R(*)(A0, As...));

给定模板类型名称M,您可以使用以下方法获取myFunc()方法的第一个参数(如果有的话)

typename PT = decltype(firstArg(&M::myfunc))

给出PT(第一个类型参数的类型),您可以简单地模拟(在decltype()内部,使用std::declval())对myfunc()的调用来获得返回的类型。 PT类型的对象

typename RT = decltype(M::myfunc(std::declval<PT>()))

以下是完整的编译示例

#include <string>
#include <type_traits>

template <typename T, typename R>
struct MyStruct
 { static R myfunc(T); };

struct MyStructInst 
 { static double myfunc(int i) { return i; } };

template <typename R, typename A0, typename ... As>
constexpr A0 firstArg (R(*)(A0, As...));

template <typename M,
          typename PT = decltype(firstArg(&M::myfunc)),
          typename RT = decltype(M::myfunc(std::declval<PT>()))>
struct MyStruct2 
 { using type1 = PT; using type2 = RT; };

int main ()
 {
   static_assert( std::is_same<int,
      typename MyStruct2<MyStructInst>::type1>{}, "!");
   static_assert( std::is_same<double,
      typename MyStruct2<MyStructInst>::type2>{}, "!");
   static_assert( std::is_same<long,
      typename MyStruct2<MyStruct<long, std::string>>::type1>{}, "!");
   static_assert( std::is_same<std::string,
      typename MyStruct2<MyStruct<long, std::string>>::type2>{}, "!");
 }