在现代 C++ 中有没有什么好的方法来获取 arg 类型列表形式的函数指针?

Is there any good way to obtain the arg type list form function pointer in modern c++?

假设我有函数指针R(*fp)(...A)。有什么方法可以获取类型 R 和类型列表 A... 吗? std::invoke_result_t 好像不行。我找不到参数列表的任何内容。

#include <iostream>
#include <cstdlib>
#include <type_traits>
typedef int(*fp_t)(int, float);
std::invoke_result_t<fp_t> x = 10;
int main()
{
    std::cout << "Hello, Wandbox!" << std::endl;
    std::cout << x << std::endl;
}

用 c++17 编译给出错误:

/opt/wandbox/gcc-head/include/c++/10.0.0/type_traits: In substitution of 'template<class _Fn, class ... _Args> using invoke_result_t = typename std::invoke_result::type [with _Fn = int (*)(int, float); _Args = {}]':
prog.cc:6:26:   required from here
/opt/wandbox/gcc-head/include/c++/10.0.0/type_traits:2917:11: error: no type named 'type' in 'struct std::invoke_result<int (*)(int, float)>'
 2917 |     using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;

变化:

std::invoke_result_t<fp_t>

至:

std::invoke_result_t<fp_t, int, float> x = 10;

因为您还需要方法参数的类型,正如@Fureeish 在 ref 中评论和确认的那样。

使用 Clang 编译它(如 ) and see the Live demo.

中所建议

不确定您到底想要什么,但在我看来您正在寻找 std::function 演绎指南(在 C++17 中引入)。

using fnT = decltype(std::function{std::declval<fp_t>()}); 

你获得一个std::function<int(int, float)>.

添加以下自定义类型特征

template <typename>
struct toTuple;

template <typename R, typename ... As>
struct toTuple<std::function<R(As...)>>
 {
   using retType  = R;
   using argTypes = std::tuple<As...>;
 };

你可以获得return类型

using rT  = typename toTuple<fnT>::retType;

或带有参数

std::tuple
using asT = typename toTuple<fnT>::argTypes;

使用std::tuple_element_t你可以提取单个参数类型。

下面是一个完整的编译示例

#include <tuple>
#include <iostream>
#include <functional>
#include <type_traits>

typedef int(*fp_t)(int, float);

template <typename>
struct toTuple;

template <typename R, typename ... As>
struct toTuple<std::function<R(As...)>>
 {
   using retType  = R;
   using argTypes = std::tuple<As...>;
 };


int main()
 {
   using fnT = decltype(std::function{std::declval<fp_t>()});
   using rT  = typename toTuple<fnT>::retType;
   using asT = typename toTuple<fnT>::argTypes;

   static_assert( std::is_same_v<fnT, std::function<int(int, float)>> );
   static_assert( std::is_same_v<rT, int> );
   static_assert( std::is_same_v<std::tuple_element_t<0u, asT>, int> );
   static_assert( std::is_same_v<std::tuple_element_t<1u, asT>, float> );
 }

使用模板元函数推导它们:

#include <tuple>
typedef int(*fp_t)(int, float);

template <class T>
struct function_signature{};

template <class Return, class... Args>
struct function_signature<Return(*)(Args...)> {
    using return_type = Return;
    using args = std::tuple<Args...>;
};

int main()
{
    using ret = function_signature<fp_t>::return_type;
    using args = function_signature<fp_t>::args;
}