在 2016 年的开明时代,自从提出这个问题以来,我们有了两个新标准,一个新标准即将到来,要知道的关键是支持 C++17 标准的编译器将按原样编译您的代码.
C++17 中类模板的模板参数推导
这里(由 Olzhas Zhumabek 对已接受答案的编辑提供)是详细说明标准相关更改的论文。
解决其他答案的担忧
当前评分最高的答案
这个答案指出“复制构造函数和operator=
”不知道正确的模板特化。
这是无稽之谈,因为标准的复制构造函数operator=
只存在于已知的模板类型:
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm; // WHAT IS THIS?
*pm = m;
在这里,正如我在评论中指出的那样,没有理由在MyClass *pm
有或没有新的推理形式的情况下进行合法声明:MyClass
不是类型(它是模板),因此声明指针是没有意义的类型MyClass
。这是修复示例的一种可能方法:
MyClass m(string("blah blah blah"));
decltype(m) *pm; // uses type inference!
*pm = m;
在这里,pm
已经是正确的类型,因此推断是微不足道的。此外,在调用复制构造函数时不可能意外混合类型:
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
在这里,pm
将是一个指向m
. 在这里,MyClass
是从m
-which 的类型MyClass<string>
(而不是不存在的类型MyClass
)复制构造的。因此,在pm
推断出 的类型时,有足够的信息可以知道 的模板类型m
以及 的模板类型pm
是string
。
此外,以下总是会 引发编译错误:
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
这是因为复制构造函数的声明没有模板化:
MyClass(const MyClass&);
这里,copy-constructor 参数的模板类型与整个类的模板类型匹配;即当MyClass<string>
被实例化时,MyClass<string>::MyClass(const MyClass<string>&);
用它实例化,当MyClass<int>
被实例化时,MyClass<int>::MyClass(const MyClass<int>&);
被实例化。除非明确指定或声明模板化构造函数,否则编译器没有理由实例化MyClass<int>::MyClass(const MyClass<string>&);
,这显然是不合适的。
Cătălin Pitiş 的答案
Pitiş 给出了一个演绎Variable<int>
和的例子Variable<double>
,然后说:
我在两种不同类型(变量和变量)的代码中具有相同的类型名称(变量)。从我的主观角度来看,它非常影响代码的可读性。
正如前面的例子中提到的,Variable
它本身并不是一个类型名,尽管新特性使它在语法上看起来像一个类型名。
Pitiş 然后询问如果没有给出允许适当推理的构造函数会发生什么。答案是不允许推理,因为推理是由构造函数调用触发的。没有构造函数调用,就没有推理。
这类似于询问foo
此处推导出的版本:
template <typename T> foo();
foo();
答案是该代码是非法的,原因已说明。
MSalter的回答
据我所知,这是对提议的功能提出合理担忧的唯一答案。
例子是:
Variable var(num); // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?
关键问题是,编译器是选择这里的类型推断构造函数还是复制构造函数?
试一下代码,我们可以看到复制构造函数被选中了。扩展示例:
Variable var(num); // infering ctor
Variable var2(var); // copy ctor
Variable var3(move(var)); // move ctor
// Variable var4(Variable(num)); // compiler error
我不确定提案和标准的新版本如何指定这一点;它似乎是由“演绎指南”决定的,这是一种我还不明白的新标准。
我也不确定为什么var4
扣除是非法的;g++ 的编译器错误似乎表明该语句被解析为函数声明。