我想知道这段代码是否合法(当然,在C ++ 17中):
template<typename T = int>
class C {};
int main() {
C c;
}
在GCC 8.1.0上可以正常编译,在Clang 6.0.0上则可以失败。我试图在标准中找到答案,但我不是语言律师,所以无法弄清楚。另一方面,cppreference指出:
std::less l; // same as std::less<void> l;
那么,是否可以定义一个类型为模板类的对象,而其中的所有模板参数都具有默认值,而无需使用尖括号?
编辑
我试图澄清我的疑问:我的代码经过稍作修改,即将main
的主体更改为
C<> c;
是来自C ++ 98的合法代码。在C ++ 17标准中,我们可能认为在这种情况下空尖括号不再是必需的?
答案 0 :(得分:4)
那么,是否可以定义一个类型为模板类的对象,而所有模板参数都具有默认值,而无需使用方括号?
简短的回答是。整个机制类似于(实际上是基于)函数模板参数推导。在推导类模板的模板参数时,将通过类似于函数调用的重载解析过程来考虑推导指南(由用户提供和由编译器生成)。
出于相同的原因,您可以做您想做的事情:
template<typename T = void>
void foo() {}
int main() {
foo();
}
我们称foo
不带尖括号,而T
为void
,因为它不是推导的,必须从默认参数中获取。
答案 1 :(得分:3)
通过对假设的类类型的对象进行初始化来执行类模板自变量的推论:
class hypothetical_C {
template <typename T = int>
hypothetical_C();
// other constructors
};
根据[over.match.class.deduct]/1:
在解析名称为主类模板C的推导类类型([dcl.type.class.deduct])的占位符解析时,会形成一组函数和函数模板,包括:
如果定义了C,则对于C的每个构造函数,一个具有以下属性的函数模板:
模板参数是C的模板参数,后跟构造函数的模板参数(包括默认模板参数)。
函数参数的类型是构造函数的类型。
返回类型是C指定的类模板特化和与C的模板参数相对应的模板参数。
...
按照[dcl.init]和[over.match.ctor],[over.match.copy]或[over.match.list]中所述执行初始化和重载解析(根据初始化类型而定)对于假设的类类型的对象,其中选择的函数和函数模板被认为是该类类型的构造函数,以形成重载集,并且初始化器由上下文提供,在该上下文中,类模板参数作为参数进行演绎。
Since there is no initializer,对象为default-initialized,因此选择了构造器模板专门化hypothetical_C<int>()
。最后,根据[dcl.type.class.deduct]/1:
如果推导类类型的占位符在变量的初始化声明([dcl.init])的decl-specifier-seq中作为decl-specifier出现,则该占位符将被返回类型替换重载解析选择的用于类模板推导的功能([over.match.class.deduct])。
推断类模板参数为int
。