【发布时间】:2011-05-26 17:52:18
【问题描述】:
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版本吗?还是我误解了什么?
编辑:进一步的证据:Defect Report 403 表明将类型(在这种情况下,函数调用表达式的参数类型)说成是一个 template-id 是不正确的,因为 template-id 有句法意义,而不是语义意义。后来的标准草案在 3.4.2 中使用了“类模板专业化”而不是“template-id”。
这支持了尽管A<B> 和C 代表相同类型(并且具有相同或几乎相同的语义),但A<B> 是一个模板id 和C 的论点不是,因为术语 template-id 将句法内容称为一系列标记,而不是这些标记的含义。
【问题讨论】:
-
不写作为答案,因为我没有时间根据标准来验证它,但我的直觉告诉我
typedef会为类型生成alias,而不是新类型.因此,应该可以在使用原始类型的任何地方使用它。请注意,这似乎也被 g++ 接受:struct A { void foo(); }; typedef A B; void B::foo() {} int main() { A a; a.foo(); } -
@David:关于“任何地方”,一个例外是定义构造函数或析构函数,其中必须使用原始类名。在另一个方向有一个有趣的例外,你不能写
(42).~int(),但是当Integer是int的typedef时你可以写(42).~Integer()。这与是否属于句法级别有关。而且我猜 OP 问题的症结与句法级别的区别有关。 -
我会指出 GCC 3.4.5 已经很老了,并且接受了很多不合法的 C++ 内容。并且不接受一些合法的东西。但是 Alf 对 Comeau 的在线评论是比较有力的证据,因为 Comeau 的编译器非常好。
-
@Alf P. Steinbach:谢谢,我不知道。每天你都必须学习新东西……现在我可以回去睡觉了。
标签: c++ templates language-lawyer explicit-specialization