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]在类模板的显式特化声明中,类模板的成员或类成员模板,显式专用的类的名称应为template-id。
此要求是否必须在本示例的末尾使用非typedef版本?或者我误解了什么?
编辑:进一步证据:Defect Report 403表明说一个类型(在该上下文中,函数调用表达式的参数类型)是 template-id 是不正确的因为 template-id 具有句法意义,而不是语义意义。后来的标准草案在3.4.2中使用了“类模板专业化”而不是“ template-id ”。
这支持这样的论点:虽然A<B>
和C
表示相同的类型(并且具有相同或几乎相同的语义含义),但A<B>
是 template-id 和C
不是,因为术语 template-id 将句法内容称为标记序列而不是那些标记的含义。
答案 0 :(得分:4)
我认为这是严重错误的(至少根据C ++ '03)。
我的逻辑是虽然是typedef(7.1.3 / 1):
...因此是另一种类型的同义词。
该标准仍然有明确允许在需要class-name
的情况下使用typedef的字样(7.1.3 / 4):
命名类的typedef-name是类名
template-id
没有这样的词。
答案 1 :(得分: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说明符声明的名称变为a typedef的名称。在其范围内 声明,typedef-name是 语法等同于关键字 并命名与之关联的类型 标识符的描述方式 因此,typedef-name是一个 另一种类型的同义词。一个 typedef-name不会引入新的 输入类声明的方式(9.1) 或枚举声明。
我想这段代码清楚地解释了代码中的 C 实际上是模板ID。