有人可以向我解释为什么以下工作:
template<class T> class MyTemplateClass {
public:
T * ptr;
};
int main(int argc, char** argv) {
MyTemplateClass<double[5]> a;
a.ptr = new double[10][5];
a.ptr[2][3] = 7;
printf("%g\n", a.ptr[2][3]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但这不是:
class MyClass {
public:
double[5] * ptr;
// double(*ptr)[5]; // This would work
};
int main(int argc, char** argv) {
MyClass a;
a.ptr = new double[10][5];
a.ptr[2][3] = 7;
printf("%g\n", a.ptr[2][3]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
显然,模板实例化不仅仅是模板参数的文本替换 - 这个魔术有一个简单的解释吗?
对于后者,编译器(g ++ 4.1.2)会吐出以下错误:
test.cxx:13: error: expected unqualified-id before '[' token
Run Code Online (Sandbox Code Playgroud)
第13行是该double[5] * ptr;行.
问题不是:
"为什么MyClass示例失败? - 因为C++不允许Java样式数组声明;-)".
但是:
"为什么MyTemplateClass示例会成功?"
不同之处在于C++语法.这样形成一个简单的声明:
declaration-specifier-seq init-declarator-list
Run Code Online (Sandbox Code Playgroud)
其中declaration-specifier-seq是一系列声明说明符:
simple-type-specifier: int, bool, unsigned, typedef-name, class-name ...
class-specifiers: class X { ... }
type-qualifier: const, volatile
function-specifier: inline, virtual, ...
storage-class-specifier: extern, static, ...
typedef
Run Code Online (Sandbox Code Playgroud)
你明白了.init-declarator-list是一个声明符列表,每个声明符都有一个可选的初始值设定项:
a
*a
a[N]
a()
&a = someObj
Run Code Online (Sandbox Code Playgroud)
所以一个完整的简单声明可能看起来像这样,包含3个声明符:
int a, &b = a, c[3] = { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)
类成员有特殊的规则来考虑它们出现的不同上下文,但它们非常相似.现在,你可以做到
typedef int A[3];
A *a;
Run Code Online (Sandbox Code Playgroud)
因为第一个使用typedef说明符,然后使用simple-type-specifier,然后使用像"a [N]"这样的声明符.然后第二个声明使用typedef-name"A"(简单类型说明符),然后使用类似"*a"的声明符.但是,你当然做不到
int[3] * a;
Run Code Online (Sandbox Code Playgroud)
由于"int [3]"不是如上所示的有效声明说明符-seq.
而现在,当然,模板是不是就像一个宏文本替换.模板类型参数当然被视为任何其他类型名称,它被解释为它命名的类型,并且可以出现在简单类型说明符可以出现的位置.一些C#人倾向于说C++模板"就像宏",但当然它们不是:)