为什么这个C ++类不等同于这个模板?

时间:2009-05-19 16:10:30

标签: c++ templates

有人可以向我解释为什么以下有效:

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;
}

但这不是:

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;
}

显然,模板实例化不仅仅是模板参数的文本替换 - 对这种魔法有一个简单的解释吗?

对于后者,编译器(g ++ 4.1.2)会吐出以下错误:

test.cxx:13: error: expected unqualified-id before '[' token

第13行是double[5] * ptr;行。

问题不在于:

“为什么MyClass示例失败? - 因为C ++不允许Java样式数组声明;-)”。

但是:

“为什么MyTemplateClass示例成功?”

3 个答案:

答案 0 :(得分:9)

不同之处在于C ++语法。一个简单的声明形成如下:

declaration-specifier-seq init-declarator-list

其中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

你明白了。 init-declarator-list是一个声明符列表,每个声明符都有一个可选的初始化器:

a
*a
a[N]
a()
&a = someObj

所以一个完整的简单声明可能看起来像这样,包含3个声明符:

int a, &b = a, c[3] = { 1, 2, 3 };

类成员有特殊的规则来考虑它们出现的不同上下文,但它们非常相似。现在,你可以做到

typedef int A[3];
A *a;

由于第一个使用typedef说明符,然后使用simple-type-specifier,然后使用像“a [N]”这样的声明符。然后第二个声明使用typedef-name“A”(简单类型说明符),然后使用类似“* a”的声明符。但是,你当然不能做到

int[3] * a;

由于“int [3]”不是如上所示的有效声明说明符-seq。

现在,当然,模板就像宏文本替换一样。模板类型参数当然被视为任何其他类型名称,它被解释为它命名的类型,并且可以出现在简单类型说明符可以出现的位置。一些C#人倾向于说C ++模板“就像宏”,但当然不是:)

答案 1 :(得分:3)

template<class T> MyTemplateClass {
    ...
}

更接近

template<class T> MyTemplateClass {
    typedef {actual type} T;
    ...
}

而不是简单的文字替换。

答案 2 :(得分:0)

使用指针或指针数组之间存在差异。在你要使用它之前,需要为你的数组的每个元素分配内存,是的,你在第二个例子中有一个拼写错误,你没有定义模板。