c++ - 遍历 function_traits 参数

标签 c++ templates c++11 template-meta-programming

我正在尝试做一些“模板元编程”的事情,以使将 c++ 函数暴露给 python 更容易一些。我想做的是采用现有函数并生成一个字符串,其中包含有关其返回类型和参数的信息(typeinfo 也可以)。

我正在使用一个基于关闭(从中窃取)this wordpress article 的函数特征类,而不是硬代码访问前几个参数,我想遍历它们。

我想我需要制作一个模板函数,该函数采用 size_t 值作为参数索引(因为它必须是常量),但这就是我有点迷路的地方。

我已经编写了一些代码,但我无法让它在最基本的情况下工作(更不用说我所追求的通用情况了。)

// The stolen function_traits struct...thing
template<typename T>
struct function_traits;

template<typename R, typename ...Args>
struct function_traits<std::function<R(Args...)>>
{
    static const size_t nargs = sizeof...(Args);

    using result_type = R;

    template <size_t i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

// The function of interest
int foo(float x) {
    return int(x);
}

// Recurse until one argument is left, appending the type name
// to the referenced string being passed in
template<size_t argIdx, typename R, typename ... Args>
void getArgTypes(std::string& ref) 
{
    using fun = function_traits<std::function<R(Args...)> >;
    if (argIdx == 1)
        ref.append(typeid(fun::arg<0>).name()).append("\n");
    else {
        ref.append(typeid(fun::arg<argIdx-1>).name()).append("\n");
        getArgTypes<argIdx - 1, R, Args...>(ref);
    }
}

// My test of the template function
void test() {
    std::string f = "";

    // What I'd like to do
    using fun = function_traits<std::function<decltype(foo)> >;
    getArgTypes<fun::nargs, fun::result_type, ? ? ? >;

    // But I can't even do this!
    getArgTypes<1, float, int>(f);
}

在第一种情况下,我在调用 getArgTypes 时使用我的 function_traits 结构,我不知道将什么指定为 ... Args 模板参数。在第二种情况下,MSVC 抛出错误:

Error   C1202   recursive type or function dependency context too complex

我对这个元编程/可变参数模板完全陌生,如果这是一个愚蠢的问题,我很抱歉。如果有一个不那么迂回的解决方案,我也会感兴趣。

感谢阅读!

最佳答案

  1. if (argIdx == 1)不能是运行时条件。必须将其更改为带有 std::enable_if 的编译时间.这就是错误的来源:编译器试图无休止地(递归地没有停止条件)实例化 getArgType函数模板。

  2. 所有 dependent type names必须用 typename 公布关键字,那些引用模板的必须用 template 声明关键字,例如typename fun::template arg<0>代替 fun::arg<0> .

  3. fun::arg<0>本身是一个带有嵌套 type 的结构定义。要访问它,请使用 typename fun::template arg<0>::type语法。

  4. 扩展function_traits::arg<N>::type可以用 indices trick 来完成, 特别是 typename F::template arg<Is>::type... .

#include <string>
#include <typeinfo>
#include <functional>
#include <utility>
#include <cstddef>

template <size_t argIdx, typename R, typename... Args>
auto getArgTypes(std::string& ref) 
    -> typename std::enable_if<argIdx == 1>::type
{
    using fun = function_traits<std::function<R(Args...)> >;
    ref.append(typeid(typename fun::template arg<0>::type).name()).append(" ");
}

template <size_t argIdx, typename R, typename... Args>
auto getArgTypes(std::string& ref) 
    -> typename std::enable_if<argIdx != 1>::type
{
    using fun = function_traits<std::function<R(Args...)> >;
    ref.append(typeid(typename fun::template arg<argIdx-1>::type).name()).append(" ");
    getArgTypes<argIdx - 1, R, Args...>(ref);
}

template <typename F, std::size_t... Is>
void test2(std::index_sequence<Is...>)
{
    std::string s;
    getArgTypes<F::nargs, typename F::result_type, typename F::template arg<Is>::type...>(s);

    std::cout << s;
}

void test()
{
    using F = function_traits<std::function<decltype(foo)>>;
    test2<F>(std::make_index_sequence<F::nargs>{});
}

DEMO


非常基本index_sequence实现过程如下:

template <std::size_t...> struct index_sequence {};
template <std::size_t N, std::size_t... Is> struct make_index_sequence : make_index_sequence<N-1, N-1, Is...> {};
template <std::size_t... Is> struct make_index_sequence<0, Is...> : index_sequence<Is...> {};

关于c++ - 遍历 function_traits 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32036556/

相关文章:

c++ - 从模板参数派生并调用其复制构造函数

c++ - 如何为所有 basic_string 实例编写通用模板

C++动态向下转换为具有模板模板参数的类模板是类模板或别名模板

c++ - dynamic_pointer_cast 意外行为

c++ - 交换数组的两个元素后计数反转

c++ - yum : using boost 1. 69 而不是 centos 上的默认 (1.53) 版本

c++ - 可变参数模板之谜

C++ 输入检查

python - 如何在 Django 模板中链接表单?

c++ - 制作自定义类型 "tie-able"(与 std::tie 兼容)