我试图弄清楚函数参数的隐式实例化是如何工作的。出于某些原因,在第一个示例中,bar()
调用将{12,41}
解释为初始化列表。如果我将foo
签名更改为auto foo(std::pair<int,int> bar)
,{12,41}
会隐式转换为std::pair<int,int>
。
例如
template<typename T, typename U>
auto foo(std::pair<T,U> arg) { return arg; }
auto bar() { return foo({12,41}); }
失败并显示错误:
<source>: In function 'auto bar()':
104 : <source>:104:50: error: no matching function for call to 'foo(<brace-enclosed initializer list>)'
auto bar() { return foo({12,41}); }
^
103 : <source>:103:6: note: candidate: 'template<class T, class U> auto foo(std::pair<_T1, _T2>)'
auto foo(std::pair<T,U> arg) { return arg; }
^~~
103 : <source>:103:6: note: template argument deduction/substitution failed:
104 : <source>:104:50: note: couldn't deduce template parameter 'T'
auto bar() { return foo({12,41}); }
^
但
auto foo(std::pair<int,int> arg) { return arg; }
auto bar() { return foo({12,41}); }
的工作原理。有人会关心解释原因吗?
答案 0 :(得分:13)
出于通常的原因:隐式转换往往不会以模板化函数的相同方式(或根本不会)发生。在你的第二个例子中:
auto foo(std::pair<int,int> arg) { return arg; }
auto works() { return foo({12,41}); }
foo
是一个函数,而不是函数模板。 std::pair
有一个非显式的两个参数构造函数:http://en.cppreference.com/w/cpp/utility/pair/pair。具有n个条目的大括号包可以隐式转换为具有n元隐式构造函数的类型。因此,您可以从{12,31}
隐式转换为std::pair<int, int>
。
当调用函数模板时,模板推导将尝试推导模板以使参数匹配。在此过程中,无法进行全范围的隐式转换。只允许进行非常特殊的转换:http://en.cppreference.com/w/cpp/language/template_argument_deduction。基本上,CV转换,派生到基础转换,以及一些指针限定和函数指针转换。
所以:
template <class T, class U>
auto foo(std::pair<T, U> arg) { return arg; }
auto bar() { return foo({12,41}); }
失败,因为当调用foo
时,它会尝试将模板参数替换为foo
以使调用参数和参数匹配,但不能使它们足够精确匹配。 / p>
我没有评论pair<auto, auto>
语法,但情况与更明确的语法完全相同,所以我认为这不是问题的核心。
之前已在SO上讨论过这个问题:C++ implicit type conversion with template,所以值得一读,以获取更多信息。虽然,请注意,那里接受的答案错误地表明在匹配函数模板时只允许CV资格更改;这不太正确(也许我会建议在那里进行编辑)。