让我们假设我们有这个小代码:
template<typename T>
struct Test {
Test(T t) : m_t(t) {}
T m_t;
};
int main() {
Test t = 1;
}
此代码很容易使用[T=int]
forTest
类进行编译。现在,如果我编写这样的代码:
template<typename T>
struct Test {
Test(T t) : m_t(t) {}
T m_t;
};
struct S {
Test t = 1;
};
int main() {
S s;
}
此代码编译失败,并出现以下错误:
invalid use of template-name 'Test' without an argument list
我需要像Test<int> t = 1;
一样写它作为类成员才能工作。知道为什么会这样吗?
原因
struct S {
Test t = 1;
};
不起作用是因为您实际上没有做Test t = 1;
. 类内初始值设定项只是一种方便的方法,用于告诉编译器在未提供时要初始化t
的值。 "实际"生成的是
struct S {
S() : t(1) {} // created by the compiler
Test t;
};
在这里,您可以更轻松地看到,在调用构造函数之前,t
未使用初始值设定项指定。
两个代码片段之间存在差异 - 第一个代码片段Test t = 1
声明、定义和初始化一个新变量,而第二个片段仅声明一个成员变量并指定如何初始化它。
默认成员初始值设定项仅在构造函数的上下文中相关,其成员初始值设定项列表中没有t
,并且可以轻松地有多个构造函数,每个构造函数以不同的方式初始化t
。
以下为有效C++,应推导出哪些t
类型?
struct S {
Test t = 1;
S(){}
S(int):t(1){}
S(double):t(true){}
};
如果要支持这一点,您就会遇到实现问题,即使类的类型/大小/布局依赖于可能位于不同转换单元中的构造函数的定义。因此,无法通过头文件定义包含类,例如S
(如果将定义移动到某些.cpp)。