P. *_*uez 5 c++ templates variadic-functions implicit-conversion variadic-templates
考虑以下代码
#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
}
Run Code Online (Sandbox Code Playgroud)
在第三个中,我知道不能进行模板推导,这就是明确指定模板参数的原因。但是为什么没有从void (*)(int)
to的显式转换std::function<void(int)>
?
我查找了答案,但这些是关于模棱两可的重载解决方案或模板推论,而不是相关主题。
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... ?
}
Run Code Online (Sandbox Code Playgroud)
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... ?
| ^
Run Code Online (Sandbox Code Playgroud)
来自 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.
Run Code Online (Sandbox Code Playgroud)
为什么,如果函数具有可变参数模板,则不会发生隐式转换(即使显式指定了模板参数)? 我回到 std::function ,果然,如果函数没有可变参数模板,它就可以工作。
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... ?
| ^
Run Code Online (Sandbox Code Playgroud)
有趣的是,以下修改使它在clang中编译
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.
Run Code Online (Sandbox Code Playgroud)
我试图寻找更多与可变参数模板相关的答案,但要么没有关于这个特定主题,要么在这一点上我无法理解。
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
Run Code Online (Sandbox Code Playgroud)
Foo<void,int>
不做你认为它做的事。
您认为它明确指定了 的模板参数Foo
。它实际上所做的是声明模板参数以Foo
then void
, int
and ... 开头,然后什么也没说。
因此,模板参数推导仍然会运行以找出其余参数是什么。它失败。然后你的编译器会抱怨。
看到这个
Foo<void, int> ( std::function<void(int,int)>( nullptr) );
Run Code Online (Sandbox Code Playgroud)
你会看到我们通过了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...)>> ) {}
Run Code Online (Sandbox Code Playgroud)
这也会阻止模板参数推导。
现在
Foo( std::function<void(int)>( Dummy ) ); // OK, template argument deduction
Run Code Online (Sandbox Code Playgroud)
不起作用,因为它拒绝推断论证。
你可以通过一些愚蠢的行为来支持两者:
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...)> ) {}
Run Code Online (Sandbox Code Playgroud)
但这不支持在没有更多愚蠢行为的情况下传递部分参数。
归档时间: |
|
查看次数: |
169 次 |
最近记录: |