实用的C++元编程

8

我刚读了一本名为《实用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) {});
}

我收到了一个编译错误,其中显示:“type”不是“make_tuple_of_params”的任何直接或间接基类的成员。看起来 SFINAE 没有按预期工作,因为选择了默认结构体。我该如何解决这个问题?


Lambda类型不是函数类型。 - aschepler
1
请注意,C++14中的lambda可以具有auto参数,这显然可以被视为模板化的函数对象。对于这种类型的lambda,您期望的元组类型是什么样子? - W.F.
2
这里没有SFINAE,只有模板特化的模式匹配 - Yakk - Adam Nevraumont
2个回答

6
[] (int, double, float) {}的类型是一个匿名类类型,局限于main内部,被称为闭包类型。它绝不是void (int, double, float),实际上根本不是函数类型。因此,函数类型的特化不适用,将选择主模板。(请注意,在您的代码中没有涉及SFINAE)。
至于如何解决这个问题:我认为没有一种完全通用的解决方案。对于特定的some_magic_function,可能会有一种解决方案/解决方法,但这取决于您需要该函数执行的操作。

1
关于潜在的修复方案:如果不需要捕获任何内容,将lambda转换为函数指针+[] (int, double, float) {}可能是一个选项。当然,make_tuple_of_params必须匹配函数指针和函数类型。 - Markus Mayr
@0xBADF00 这在 Markus 的评论的第二句话中已经涵盖了。 - Yakk - Adam Nevraumont

5
对于不包括自动参数的lambda表达式,解决方法如下:
``` [](int x) -> bool { return x > 0; } ```
在这种情况下,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]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接