为什么在调用构造函数时模板参数推导失败?

时间:2014-05-27 17:31:28

标签: c++ templates

以下内容无法编译:

struct S {
    template <class T> S(T) {}
};
void f(int) {}
int main() {
    S(f);
}

g ++ - 4.9说

template.cpp: In function ‘int main()’:
template.cpp:6:8: error: no matching function for call to ‘S::S()’
     S(f);
        ^
template.cpp:6:8: note: candidates are:
template.cpp:2:24: note: template<class T> S::S(T)
     template <class T> S(T) {}
                        ^
template.cpp:2:24: note:   template argument deduction/substitution failed:
template.cpp:6:8: note:   candidate expects 1 argument, 0 provided
     S(f);
        ^
template.cpp:1:8: note: constexpr S::S(const S&)
 struct S {
        ^
template.cpp:1:8: note:   candidate expects 1 argument, 0 provided
template.cpp:1:8: note: constexpr S::S(S&&)
template.cpp:1:8: note:   candidate expects 1 argument, 0 provided

clang给出了类似的错误。

另一方面,以下编译:

struct S {
    template <class T> S(T) {}
};
void f(int) {}
int main() {
    S s = S(f); // this line was changed
}

那么这里发生了什么?

2 个答案:

答案 0 :(得分:7)

问题

您编写的代码并不代表您的想法,您实际上是在声明名为S的{​​{1}}类型的变量;它是构建f类型的未命名实体,其中S为参数。

注意:当您将行更改为f时,您正在声明名为S s = S(f)的{​​{1}}类型的变量,并使用临时值初始化s(即 S copy-constructor 将用于初始化S)。


解决方案

在括号中包装类型,或使用 uniform-initialization (在C ++ 11中引入)。

S(f)

s

原因

标准(n3797)表示(S) (f); // creates a temporary of type S initialized with `f` 在声明变量时相当于S { f }; // c++11 ,可以在下面的部分中阅读:

  

8.3p6 声明者的含义 T(x)

     
    

在声明T x[dcl.meaning]的格式为

T D
         

包含的declarator-id的类型与     声明中包含 declarator-id

D
         

括号不会改变嵌入的 declarator-id 的类型,但是     他们可以改变复杂声明者的绑定。

  

答案 1 :(得分:0)

使用struct S

的定义
int main() {

    S(f);                                            //  1 <-----+
    S s(f);           //  2 <-------+                //          +---- SAME
    S s1 ;            //            +---- SAME       //  3 <-----+
    S s2 = S(f) ;     //  4 <-------+

}
  • 1&amp; 3声明变量f&amp;分别为s1的{​​{1}}需要构造函数进行初始化
  • 2&amp; 4构造一个变量S&amp; s分别使用复制构造函数s2 {注意此处S不是您的函数名称)