在开明的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
—类型MyClass<string>
(而不是不存在的类型MyClass
)复制构造的。因此,在点pm
的类型推断,存在是足够的信息来知道模板型的m
,因此,模板型的pm
,则string
。
此外,以下内容将始终 引发编译错误:
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
这是因为复制构造函数的声明未模板化:
MyClass(const MyClass&);
在这里,copy-constructor参数的template-type 与整个类的template-type 相匹配。即,何时MyClass<string>
被实例化,MyClass<string>::MyClass(const MyClass<string>&);
用它实例化,以及何时MyClass<int>
被实例化,MyClass<int>::MyClass(const MyClass<int>&);
被实例化。除非明确指定它或声明一个模板化的构造函数,否则编译器没有理由实例化MyClass<int>::MyClass(const MyClass<string>&);
,这显然是不合适的。
CătălinPitiș的回答
皮蒂ș举了一个推论Variable<int>
和的例子Variable<double>
,然后说:
我在两种不同类型(变量和变量)的代码中具有相同的类型名(变量)。从我的主观角度来看,它在很大程度上影响了代码的可读性。
如前面的示例所述,即使新功能使它在语法上看起来像一个名称,Variable
它本身也不是类型名称。
然后,Pitiș询问如果没有给出允许适当推断的构造函数,将会发生什么情况。答案是不允许推论,因为推论是由构造函数call触发的。没有构造函数调用,就没有推断。
这类似于询问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 ++的编译器错误似乎表明该语句已被解析为函数声明。