简体   繁体   English

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

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

Let's consider the following functions:让我们考虑以下功能:

// 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...);
}

Now if I want to use these functions as follows:现在,如果我想按如下方式使用这些功能:

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;
}

I get a "no matching function call" with run_cb_2() and run_cb_3() while it works perfectly fine with run_cb_1() .我使用run_cb_2()run_cb_3()得到“没有匹配的 function 调用” ,而它与run_cb_1()完美配合。

I think it behaves as expected because I did not provided the type for the template argument (since it can not be deduced trivially as it is for run_cb_1() ).我认为它的行为符合预期,因为我没有提供模板参数的类型(因为它不能像run_cb_1()那样简单地推断出来)。

But specifying the template type solves the problem for run_cb_2() (as I would expect) but not for run_cb_3() .但是指定模板类型可以解决run_cb_2()的问题(如我所料),但不能解决run_cb_3()的问题。


I know I can solve it either by explicitly declaring f as:我知道我可以通过明确声明f来解决它:

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

or by passing f as:通过 f 传递:

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

My question is: Why does the template argument deduction fail with run_cb_3() (with variadic template parameters) even when explicitly specifying the template type(s)?我的问题是:为什么即使明确指定模板类型,模板参数推导run_cb_3() (带有可变参数模板参数)而失败?

It is obvious that I missed something (maybe basic) but I don't know what it is.很明显,我错过了一些东西(也许是基本的),但我不知道它是什么。
Any help will be appreciated.任何帮助将不胜感激。

The reason this fails is because there isn't just one type the compiler can use.失败的原因是编译器可以使用的类型不止一种。 When you do当你这样做

run_cb_2<int>(f, 5);

The compiler looks at run_cb_2 and sees that there is only one template parameter.编译器查看run_cb_2并看到只有一个模板参数。 Since you've provided that it skips the deduction phase and stamps out run_cb_2<int> .由于您已提供它跳过扣除阶段并标记出run_cb_2<int>

With

run_cb_3<int>(f, 5);

You're in a different boat.你在另一条船上。 run_cb_3 has a variadic template parameter which means just supplying int is not enough to skip the deduction. run_cb_3有一个可变参数模板参数,这意味着仅提供int不足以跳过扣除。 You specified the first argument, but there could be more so it goes into the argument deduction phase to figure it out.您指定了第一个参数,但可能还有更多参数,因此它会进入参数推导阶段以找出答案。 That means it checks callback to make sure what it deduces there matches what it deduces for args .这意味着它会检查callback以确保它在那里推断出的内容与它为args推断出的内容相匹配。 Since the lambda is not a std::function it can't deduce Args... from it.由于 lambda 不是std::function它不能从中推断出Args... Once that happens the compiler stops and issues an error.一旦发生这种情况,编译器就会停止并发出错误。

With run_cb_3<int> , you don't explicitly provide full Args... , just the first type;使用run_cb_3<int> ,您无需明确提供完整的Args... ,只是第一种类型; it might have other.它可能还有其他。

It is used for example in function such as std::make_unique :例如在 function 中使用它,例如std::make_unique

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

and

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

Extra args are deduced from argument.额外的参数是从参数推导出来的。

To force evaluation, you might use:要强制评估,您可以使用:

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

Demo演示

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

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