函数参数的隐式实例化

时间:2017-08-22 13:07:51

标签: c++ c++17

我试图弄清楚函数参数的隐式实例化是如何工作的。出于某些原因,在第一个示例中,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}); }

的工作原理。有人会关心解释原因吗?

1 个答案:

答案 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资格更改;这不太正确(也许我会建议在那里进行编辑)。