繁体   English   中英

为什么模板参数推导因 std::function 回调的可变参数模板参数而失败?

[英]Why does template argument deduction failed with variadic template parameters of a std::function callback?

让我们考虑以下功能:

// run_cb_1(): Explicitly defined prototype
void run_cb_1(const std::function<void(int)> & callback, int p)
{
    callback(p);
}

// run_cb_2(): One template parameter
template <typename T>
void run_cb_2(const std::function<void(T)> & callback, const T & t)
{
    callback(t);
}

// run_cb_3(): Variable number of template parameters
template <typename ... Args>
void run_cb_3(const std::function<void(Args...)> & callback, const Args & ... args)
{
    callback(args...);
}

现在,如果我想按如下方式使用这些功能:

int main()
{
    auto f = [](int a){
        std::cout << a << '\n';
    };

    run_cb_1(f, 5);      // OK

    run_cb_2(f, 5);      // KO --> I understand why
    run_cb_2<int>(f, 5); // OK

    run_cb_3(f, 5);      // KO --> I understand why
    run_cb_3<int>(f, 5); // KO --> I don't understand why...

    return 0;
}

我使用run_cb_2()run_cb_3()得到“没有匹配的 function 调用” ,而它与run_cb_1()完美配合。

我认为它的行为符合预期,因为我没有提供模板参数的类型(因为它不能像run_cb_1()那样简单地推断出来)。

但是指定模板类型可以解决run_cb_2()的问题(如我所料),但不能解决run_cb_3()的问题。


我知道我可以通过明确声明f来解决它:

std::function<void(int)> f = [](int a){
    std::cout << a << '\n';
};

通过 f 传递:

run_cb_2(std::function<void(int)>(f), 5);
run_cb_3(std::function<void(int)>(f), 5);

我的问题是:为什么即使明确指定模板类型,模板参数推导run_cb_3() (带有可变参数模板参数)而失败?

很明显,我错过了一些东西(也许是基本的),但我不知道它是什么。
任何帮助将不胜感激。

失败的原因是编译器可以使用的类型不止一种。 当你这样做

run_cb_2<int>(f, 5);

编译器查看run_cb_2并看到只有一个模板参数。 由于您已提供它跳过扣除阶段并标记出run_cb_2<int>

run_cb_3<int>(f, 5);

你在另一条船上。 run_cb_3有一个可变参数模板参数,这意味着仅提供int不足以跳过扣除。 您指定了第一个参数,但可能还有更多参数,因此它会进入参数推导阶段以找出答案。 这意味着它会检查callback以确保它在那里推断出的内容与它为args推断出的内容相匹配。 由于 lambda 不是std::function它不能从中推断出Args... 一旦发生这种情况,编译器就会停止并发出错误。

使用run_cb_3<int> ,您无需明确提供完整的Args... ,只是第一种类型; 它可能还有其他。

例如在 function 中使用它,例如std::make_unique

template <class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args);

std::make_unique<MyObj>(var1, var2); // T = MyObj
                                     // Args... = [decltype((var1)), decltype((var2))]

额外的参数是从参数推导出来的。

要强制评估,您可以使用:

(&run_cb_3<int>)(f, 5); // OK

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM