我试图弄清楚函数参数的隐式实例化是如何工作的.由于某些原因,在第一个示例中,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}); }
Run Code Online (Sandbox Code Playgroud)
失败并出错:
<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}); }
^
Run Code Online (Sandbox Code Playgroud)
但
auto foo(std::pair<int,int> arg) { return arg; }
auto bar() { return foo({12,41}); }
Run Code Online (Sandbox Code Playgroud)
作品.有人会关心详细说明原因吗?
Nir*_*man 13
出于通常的原因:隐式转换往往不会以模板化函数的相同方式(或根本不会)发生.在你的第二个例子中:
auto foo(std::pair<int,int> arg) { return arg; }
auto works() { return foo({12,41}); }
Run Code Online (Sandbox Code Playgroud)
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}); }
Run Code Online (Sandbox Code Playgroud)
失败,因为在foo调用时,它会尝试将模板参数替换为foo调用参数并使参数匹配,但不能使它们足够精确地匹配.
我没有评论pair<auto, auto>语法,但情况与更明确的语法完全相同,所以我不认为这是问题的核心.
之前在SO上讨论过这个问题:使用模板进行C++隐式类型转换,因此值得阅读以获取更多信息.虽然,请注意,那里接受的答案错误地表明在匹配函数模板时只允许CV资格更改; 这不太正确(也许我会建议在那里编辑).