在模板化类型上编译时间循环

时间:2014-09-25 19:49:15

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

我一直在搜索SO和其他论坛,寻找确定lambda的参数和返回类型的方法,然后对这些参数进行操作,以便对已经存在的对象的repo进行类型查找实例化。关键是要创建一种方法来对某些任意定义的lambda表达式进行依赖注入。例如,如果我有以下内容:

auto lambda = [] (MyObject o) -> string { return o.name(); };

我可以确定lambda的参数类型,并查找类型为MyObject的相应对象,然后调用lambda“自动”传递该对象。

到目前为止,我已经找到了使用以下模板确定lambdas参数列表类型和返回类型的方法:

template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
    // we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };
    // arity is the number of arguments.

    typedef ReturnType result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
        // the i-th argument is equivalent to the i-th tuple element of a tuple
        // composed of those arguments.
    };
};

我在this SO发现的帖子(非常整洁)。

现在,我想做的是实现某种类似于以下的编译时间:

// first get the type of the lambda using the above 'function_traits' template
typedef function_traits<decltype(lambda)> traits;
// now iterate over the traits and get the type of each argument, then print out the type name
for (size_t i = 0u; i < size_t(traits::arity); ++i)
{
  // The point to focus on here is `traits::args<i>::type`
  std::cout << typeid(traits::args<i>::type).name() << std::end;
}

我上面发布的内容是不可能的。上面代码中的问题是i不是常量,并且在运行时进行评估,而不是编译时(评估此模板魔法的其余部分)。我尝试了一些不同的方法来试图找到一种方法(它们之间的模板递归),但我找不到能够完全符合我想要的解决方案。

所以,问题的根源在于,你如何“迭代”模板?我是TMP的新手,并且从运行时到编译时逻辑的精神转变一直是一个挑战。如果有人对新手有一些建议会很棒。

1 个答案:

答案 0 :(得分:1)

使用C ++ 14,您可以:

namespace detail
{
    template <typename T, std::size_t ... Is>
    void display(std::index_sequence<Is...>)
    {
        std::initializer_list<int>{((std::cout << typeid(typename T::template arg<Is>::type).name() << std::endl), 0)...};
    }

}

template <typename T>
void display()
{
    detail::display<T>(std::make_index_sequence<T::arity>());
}

并使用它:

using traits = function_traits<decltype(lambda)>;

display<traits>();

Live example

如果你坚持使用C ++ 11,那么有很多地方可以找到make_index_sequenceindex_sequence的实现