gpt4 book ai didi

c++ - 可变参数函数中可变参数模板类的隐式转换

转载 作者:行者123 更新时间:2023-12-04 11:41:07 28 4
gpt4 key购买 nike

考虑以下代码

#include <functional>
template<class ResultType, class ... Args>
void Foo( std::function<ResultType(Args...)> ) {}

void Dummy(int) {}

int main()
{
Foo<void, int> ( std::function<void(int)>( Dummy ) ); // OK, no deduction and no conversion
Foo( std::function<void(int)>( Dummy ) ); // OK, template argument deduction
Foo<void, int>( Dummy ); // Compile error
}

在第三个中,我知道不能进行模板推导,这就是明确指定模板参数的原因。 但是为什么没有来自 void (*)(int) 的显式转换至 std::function<void(int)> ?

我查找了答案,但这些是关于模棱两可的重载解决方案或模板推论,而不是相关主题。

Isn't the template argument (the signature) of std::function part of its type?

Template type deduction with std::function

Implicit conversions with std::function

然后我尝试使用我自己的模板类而不是 std::function 进行测试。

// Variadic template class
template<class ... T>
class Bar
{
public:
// Non-explicit ctor, an int can go through implicit conversion
Bar(int) {}
};

// A template function
template<class T>
void Xoo( Bar<T> ) {}

// Same, but this one has a variadic template
template<class ... T>
void Yoo( Bar<T...> ) {}

int main()
{
Xoo( Bar<bool>( 100 ) ); //OK, argument deduction
Xoo<bool>( 100 ); //OK, implicit conversion
Yoo( Bar<bool>( 100 ) ); //OK, argument deduction
Yoo<bool>( 100 ); // Not ok... ?
}

GCC 9.2.0 的输出
prog.cc: In function 'int main()':
prog.cc:23:19: error: no matching function for call to 'Yoo<bool>(int)'
23 | Yoo<bool>( 100 ); // Not ok... ?
| ^
prog.cc:16:6: note: candidate: 'template<class ... T> void Yoo(Bar<T ...>)'
16 | void Yoo( Bar<T...> ) {}
| ^~~
prog.cc:16:6: note: template argument deduction/substitution failed:
prog.cc:23:19: note: mismatched types 'Bar<T ...>' and 'int'
23 | Yoo<bool>( 100 ); // Not ok... ?
| ^

来自 clang 9.0.0 的输出
prog.cc:23:4: error: no matching function for call to 'Yoo'
Yoo<bool>( 100 ); // Not ok... ?
^~~~~~~~~
prog.cc:16:6: note: candidate template ignored: could not match 'Bar<bool, type-parameter-0-0...>' against 'int'
void Yoo( Bar<T...> ) {}
^
1 error generated.

为什么,如果函数具有可变参数模板,则不会发生隐式转换(即使显式指定了模板参数)?
我回到 std::function ,果然,如果函数没有可变参数模板,它就可以工作。

#include <functional>
// Not variadic this time
template<class ResultType, class Arg>
void Goo( std::function<ResultType(Arg)> ) {}
void Dummy(int) {}
int main()
{
Goo<void, int> ( Dummy ); // Ok this time
}

有趣的是,以下修改使它在clang中编译

[...]

// Same, but this one has a variadic template
template<class ... T>
void Yoo( Bar<T..., bool> ) {}
// ^^^^
// An extra template for Bar makes implicit conversion
// work for some reason

[...]

我试图寻找与可变参数模板相关的更多答案,但要么没有关于这个特定主题,要么在这一点上我无法理解。

How to overload variadic templates when they're not the last argument

Template parameter pack deduction when not passed as last parameter

Deduction guides and variadic class templates with variadic template constructors - mismatched argument pack lengths

Template argument and deduction of std::function parameters

Deduction guides and variadic class templates with variadic template constructors - mismatched argument pack lengths

最佳答案

template<class ResultType, class ... Args>
void Foo( std::function<ResultType(Args...)> ) {}

Foo<void, int> ( std::function<void(int)>( Dummy ) ); // OK, no deduction and no conversion
Foo( std::function<void(int)>( Dummy ) ); // OK, template argument deduction
Foo<void, int>( Dummy ); // Compile error
Foo<void,int>不会做你认为它会做的事情。
您认为它明确指定了 Foo 的模板参数。 .它实际所做的是声明 Foo 的模板参数 开始 void然后是 int ,然后......然后它什么也没说。
所以模板参数推导仍然运行以找出其余参数是什么。它失败。然后你的编译器提示。
看到这个
 Foo<void, int> ( std::function<void(int,int)>( nullptr) );
你会看到我们通过了 void,int ,但推导出的是 void,int,int -- 二 int不是一个。
...
对于您的特定问题,您将模板参数推导与类型删除类型( std::function )混合在一起,并且同时执行它们很像给汽车喷漆,因为您想剥掉油漆。
模板参数推导和类型删除操作不完善 反转 彼此的。
当剩下一个可变包时,一旦你传递了每个参数,就不需要进行推导,因此它不再进行模板参数推导。
如果您的 Bar<T...,bool>您正在阻止参数推导,因为 C++ 拒绝在包之后有任何东西时推导包。
如果你真的想要这个,你可以这样做:
template<class T>
struct identity { using type=T; };
template<class T> using identity_t = typename identity<T>::type;

template<class ResultType, class ... Args>
void Foo( identity_t<std::function<ResultType(Args...)>> ) {}
这也阻止了模板参数推导。
现在
Foo( std::function<void(int)>( Dummy ) ); // OK, template argument deduction
不起作用,因为它拒绝推断论点。
你可以用一点傻瓜来支持两者:
template<class ResultType, class ... Args>
void Foo( identity_t<std::function<ResultType(Args...)>> ) {}

struct never_use {};
template<class R0=never_use, class ResultType, class ... Args>
requires (std::is_same_v<R0, never_use>)
void Foo( std::function<ResultType(Args...)> ) {}
但这不支持在没有更多傻瓜的情况下传递部分参数。

关于c++ - 可变参数函数中可变参数模板类的隐式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59573624/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com