4

g++ 3.4.5 接受此代码:

template <typename T> struct A
{
    static const char* const str;
};

struct B {};

typedef A<B> C;

template<> const char* const C::str = "B";
// Equivalent to following?
// template<> const char* const A<B>::str = "B";

但我不确定它实际上是合法的 C++03。尤其,

[14.7p3] 在类模板、类模板的成员或类成员模板的显式特化声明中,显式特化的类的名称应为模板 ID。

这个要求是说在这个例子的最后必须使用非 typedef 版本吗?还是我误解了什么?

编辑:进一步的证据:缺陷报告 403表明将类型(在该上下文中,函数调用表达式的参数类型)说成是模板 ID是不正确的,因为模板 ID具有句法含义,而不是语义一。后来的标准草案在 3.4.2中使用了“类模板专业化”而不是“模板 ID ”。

这支持了这样的论点,即尽管A<B>C表示相同的类型(并且具有相同或几乎相同的语义含义),但A<B>它是一个模板 IDC不是,因为术语模板 ID将句法内容指代为一系列标记而不是这些标记的含义。

4

2 回答 2

4

我认为这是严格格式错误的(至少根据 C++ '03)。

我的逻辑是,虽然 typedef (7.1.3/1):

...因此是另一种类型的同义词。

该标准仍然明确允许在需要 a 的地方使用 typedef class-name(7.1.3/4):

命名类的 typedef-name 是类名

没有这样的词template-id

于 2010-12-16T19:46:19.063 回答
0

我想那里没有明确的专业化。您可以在没有模板的情况下编写类似的代码:

struct A
{
    static const char* const str;
};

typedef A C;

const char* const C::str = "B";

即使您使用 C 而不是 A,此代码也是绝对正确的。C 只是一个别名。

想象一下如何处理 C++ 代码。Typedef 显然在模板实例化过程开始之前就被编译器扩展了。与在宏之前扩展所有注释相同。因为在实际的 C++ 解析开始之前,所有的宏都被预处理器扩展了。这简化了一切。

关于 C++03 标准,看看那个

7.1.3/1 使用 typedef 说明符声明的名称成为 typedef-name。在其声明的范围内,typedef-name 在 语法上等同于关键字,并以第 8 节中描述的方式命名与标识符关联的类型。因此 typedef-name 是另一种类型的同义词。typedef-name 不会像类声明 (9.1) 或枚举声明那样引入新类型。

我想这一段清楚地解释了代码中的C实际上是一个模板 ID。

于 2010-12-16T19:10:13.177 回答