在2016年这个开明的时代,自从提出这个问题以来,我们已经有了两个新的标准,并且还有一个新的标准即将发布。关键要知道的是,支持C++17标准的编译器将会原样编译您的代码。
C++17中的类模板模板参数推导
这里(感谢Olzhas Zhumabek编辑的答案)详细介绍了相关标准的变化。
解决其他答案中的问题
当前排名第一的答案指出,“复制构造函数和operator=”无法知道正确的模板特化。
这是荒谬的,因为标准的复制构造函数和operator=只存在于已知的模板类型中。
template <typename T>
class MyClass {
MyClass(const MyClass&) =default;
... etc...
};
MyClass m(string("blah blah blah"));
MyClass *pm;
*pm = m;
在这里,正如我在评论中指出的那样,没有理由让
MyClass *pm
成为一个合法的声明,无论是否使用新形式的推断:
MyClass
不是一种类型(它是一个模板),所以声明一个
MyClass
类型的指针是没有意义的。以下是修复示例的一种可能方式:
MyClass m(string("blah blah blah"))
decltype(m) *pm
*pm = m
在这里,
pm
已经是正确的类型,因此推理是微不足道的。此外,在调用复制构造函数时,不可能意外地混合类型:
mix。
MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));
这里,pm
将是指向m
的副本的指针。这里,MyClass
正在从类型为MyClass<string>
(而不是不存在的类型MyClass
)的m
进行复制构造。因此,在推断pm
的类型的点上,有足够的信息可以知道m
的模板类型,因此pm
的模板类型是string
。
此外,以下内容始终会引发编译错误:
MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;
这是因为复制构造函数的声明
不是模板化的。
MyClass(const MyClass&)
这里,复制构造函数的参数模板类型“匹配”类的整体模板类型;即,当实例化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和Variable)的相同类型名(Variable)。从我的主观角度来看,这对代码的可读性影响很大。
正如前面的例子所述,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>> ?
关键问题是,编译器在这里选择的是
类型推断构造函数还是
拷贝构造函数?
通过尝试代码,我们可以看到选择了拷贝构造函数。
为了进一步说明这个例子:
int num = 3;
Variable var(num);
Variable var2(var);
Variable var3(move(var));
Variable var4{Variable(num)};
我不确定提案和新版本的标准如何具体规定这一点;它似乎是由“推导指南”决定的,这是一种我尚未理解的新标准术语。
由于“最令人烦恼的解析”(该语句被解析为函数声明),
var4
的推导是非法的。我不完全确定原因,因为对我来说,这看起来不像一个有效的函数声明语法。
template<class T> Variable<T> make_Variable(T&& p) {return Variable<T>(std::forward<T>(p));}
- Mooing Duck