使用C++ 11可变参数模板进行奇怪的替换失败

use*_*691 8 variadic-templates c++11

我很难弄清楚这个示例代码中导致替换失败的原因:

bool f(int a, int b, float c)
{
    printf("%d %d %f", a, b, c);
    return true;
}

template <typename ...Params>
void call1(Params... params, std::function<bool(Params...)> func)
{
    func(params...);
}

template <typename ...Params>
void call2(std::function<bool(Params...)> func)
{
}
Run Code Online (Sandbox Code Playgroud)

主要的地方:

call1<int, int, float>(3, 4, 5.5, f); // Ok.
call2<int, int, float>(f); // Substitution failure.
Run Code Online (Sandbox Code Playgroud)

编译器说:

template argument deduction/substitution failed: mismatched types 'std::function<bool(Params ...)>' and 'bool (*)(int, int, float)'
call2<int, int, float>(f);
                          ^
Run Code Online (Sandbox Code Playgroud)

令我感到困惑的是call1有效,而call2没有.有小费吗?=)

Gui*_*nal 3

第一:您可以指定比您使用的参数更少的参数,然后让编译器推断出其余的参数:

template <typename ...Params>
void func1(Params... params);

func1<int, int>(1, 2, 3); // calls func1<int, int, int>
Run Code Online (Sandbox Code Playgroud)

当您调用它时,这意味着Params仍然可以添加额外的类型。但是如果你获取函数地址,它就会被定义并关闭:

auto x = func1<int, int>;
x(1, 2, 3); // not possible
Run Code Online (Sandbox Code Playgroud)

当您call1直接调用函数时:

template <typename... Params>
void call1(Params... params, std::function<bool(Params...)> func);

call1<int, int, int>(1, 2, 3, f);
call1<int>(1, 2, 3, f); // same as before
call1(1, 2, 3, f); // same as before
Run Code Online (Sandbox Code Playgroud)

编译器能够推断出您正好有 3 个整数,因为您刚刚向他发送了 3 个整数。这样最后一个参数一定是std::function<bool(int, int, int)>因为我们完全推导了Params...含义并且没有空间容纳更多类型。

现在有问题的情况:

template <typename... Params>
void call2(std::function<bool(Params...)> func);

call2<int, int, int>(f);
Run Code Online (Sandbox Code Playgroud)

这里你告诉编译器 的前 3 个元素Params都是整数。Params = {int, int, int, ...}。请注意,如果推论表明如此,它仍然可以添加其他内容。替换我们有:std::function<bool(int, int, int, ...)> func。除非您显式传递(完全匹配),否则编译器不可能知道这个不完整类型的含义std:function。它还不知道它可以有一个构造函数来获取您提供的函数指针,因此存在不匹配。现在编译器没有足够的数据来决定是否需要更多类型Params。失败。

但请注意这个有趣的案例:

auto x = call2<int, int, int>;
x(f); // x is exactly void(*)(std::function<bool(int, int, int)>). No doubts.
Run Code Online (Sandbox Code Playgroud)

在这里你强迫自己Params完整。没有扣除可以评估。虽然丑陋,但这也有效:

(&call2<int, int, int>)(f);
Run Code Online (Sandbox Code Playgroud)