2016-11-29 29 views
8

我刚刚阅读了一本书“Practical C++ Metaprogramming”,它有以下示例,我无法编译。你能帮我解决这个问题吗?实用C++元编程

template <typename F> 
struct make_tuple_of_params; 

template <typename Ret, typename... Args> 
struct make_tuple_of_params<Ret (Args...)> 
{ 
    using type = std::tuple<Args...>; 
}; 

template <typename F> 
using make_tuple_of_params_t = typename make_tuple_of_params<F>::type; 

template<typename F> 
void some_magic_function(F callable) 
{ 
    make_tuple_of_params_t<F> tuple; 
    /* 
    ... do something with arguments in tuple... 
    */ 
} 

int main() 
{ 
    some_magic_function([] (int, double, float) {}); 
} 

我得到一个编译错误说:“类型”没有任何直接或间接的基类的make_tuple_of_params'中的一员。它接缝像SFINAE不能按预期工作,因为默认结构被选中。我该如何解决?

+0

一个lambda类型不是函数类型。 – aschepler

+1

请记住,C++ 14中的lambdas可以有'auto'参数,这些参数显然可以被视为模板函子。对于这种lambda类型,你会期望你的元组类型看起来相似吗? –

+2

上面没有SFINAE,只是专门化模板模式匹配 – Yakk

回答

5

对于lambda表达式,如果不包括汽车参数lambda表达式的解决方法可能如下所示:

#include <tuple> 
#include <typeinfo> 
#include <iostream> 

template <class> 
struct make_tuple_of_params; 

template <class Res, class Type, class... Args> 
struct make_tuple_of_params<Res (Type::*)(Args...) const> { 
    using type = std::tuple<Args...>; 
}; 

template <class F> 
using make_tuple_of_params_t = typename make_tuple_of_params<F>::type; 

template<typename F> 
void some_magic_function(F callable) 
{ 
    make_tuple_of_params_t<decltype(&F::operator())> tuple; 
    std::cout << typeid(tuple).name() << std::endl; 
} 

int main() 
{ 
    some_magic_function([] (int, double, float) {}); 
} 

[live demo]

6

[] (int, double, float) {}的类型是main的局部未命名类类型,称为闭包类型。最肯定是不是void (int, double, float);它实际上不是一种功能类型。因此,功能类型的专门化不适用,并选择主模板。 (请注意,SFINAE不涉及您的代码)。

至于如何解决这个问题:我不认为有一个完全一般的解决方案。对于特定的some_magic_function可能有解决方案/解决方法,但这取决于您需要执行的功能。

+1

关于潜在的问题:如果不需要捕获任何东西,将lambda转换为带有+ [](int,double,float){}的函数指针可能是一个选项。当然,'make_tuple_of_params'必须匹配函数指针和函数类型。 –

+0

好吧,我尝试了一个函数指针,但没有成功。 – 0xBADF00

+0

@ 0xBADF00这在Markus的评论的第二句话中有介绍。 – Yakk