【问题标题】:Iterating through function_traits arguments遍历 function_traits 参数
【发布时间】:2015-08-16 15:06:59
【问题描述】:

我正在尝试做一些“模板元编程”的东西,以使将 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

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

感谢您的阅读!

【问题讨论】:

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


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

    2. 所有dependent type names 必须用typename 关键字声明,引用模板的必须用template 关键字声明,例如typename fun::template arg&lt;0&gt; 代替 fun::arg&lt;0&gt;

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

    4. function_traits::arg&lt;N&gt;::type 的扩展可以使用indices trick 来完成,尤其是typename F::template arg&lt;Is&gt;::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...> {};
    

    【讨论】:

    • 酷,谢谢!对不起我之前的“回答”;我认为有一种方法可以遍历元组,但你将不得不使用某种索引魔法,就像你在这里所做的那样。
    • 非常感谢 Piotr 提供的解决方案!这对我很有用:)
    猜你喜欢
    • 1970-01-01
    • 2011-05-23
    • 2014-05-13
    • 2021-04-08
    • 2017-12-07
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    相关资源
    最近更新 更多