11

如果此代码无效,那就太好了。但它在概念上是合理的,GCC接受它,尽管 Comeau 没有:

template< typename > struct t;

template<> struct t< int > {} r; // Bad declarator! Don't pee on the carpet!

编辑:上面的编译但r似乎没有被声明到任何范围内,所以它基本上被忽略了。)

显式特化填充了模板和类之间的一种下层区域。由显式特化声明的类型一旦定义就完成了。从编译器的角度来看,它不是模板。如果它是一个参数化的模板,那么声明一个对象是不可能的。考虑§14/3:

在模板声明、显式特化或显式实例化中,声明中的 init-declarator-list 最多应包含一个声明符。当这样的声明用于声明类模板时,不允许使用任何声明符。

“用于声明类模板”是什么意思?显然,主模板声明了一个类模板。根据 §14.5.5/1(FDIS 编号),部分专业化也是如此:

类模板名称为 simple-template-id 的模板声明是 simple-template-id 中命名的类模板的部分特化。

但是,当涉及到显式特化时,标准是根据标记序列前面的声明来说话的template<>。它看起来像一个模板,它命名了一个模板名称,但它似乎没有声明一个模板。

真正奇怪的是,§14/3 将声明符的数量限制为“最多一个”。函数模板声明、显式特化或实例化必须只有一个声明符。任何涉及类模板的声明都必须完全为零……除了显式特化,它似乎已经落入了裂缝。忠实地,海湾合作委员会拒绝允许

template<> struct t< int > {} r, s; // Offer valid one per specialization.

我倾向于同意 GCC 的解释,尽管它可能是胡说八道。不幸的是,它可能会抑制它检测丢失分号的能力。请让允许的声明符的数量完全为零!

4

2 回答 2

13

几点:首先,显式的特化不在模板和类之间的区域;一个明确的专业化是一个类,时期。与模板的唯一关系(除了有趣的名称)是,如果要在专业化类型上实例化模板,它将被使用而不是模板实例化。

其次,如果您引用的 §14/3 中的段落有问题,那就是它包含显式实例化;显式实例化是类定义,如果

struct S {} s, *p;

是合法的,

template<> struct T<int> {} s, *p;

应该也是。(我反对允许,但是那列火车已经离开了车站,而且由于 C 允许第一个,我们就坚持下去了。)

否则,§14/3 中的陈述有点无关紧要。一个函数模板必须正好有一个声明符,而一个类模板正好为零;没有必要尝试将它们都包含在一些“最多一个”的 gobbledygook 中。(如果我从头开始设计语言,我不允许在定义类或枚举类型的声明中使用任何声明符。但同样,为时已晚。)

我同意这是一个麻烦:

template<> struct T<int> {};    //  Requires a ';'
template<> void f<int>() {}     //  ';' forbidden

(至少 C++11 允许在函数定义后使用分号。)

于 2011-06-10T09:43:10.453 回答
1

显式特化和显式实例化不声明模板。他们声明了一个模板标识,它指的是一个专业化,它是一个类。

但是,这并不能验证我的示例。问题在于,所有声明的内容都分别遵循templatetemplate<>属于显式实例化或特化的一部分。只有某些类型的实体可能是专门的或实例化的,以前未声明的名称不是其中之一。

考虑这些示例,使详细但合法地使用详细类型说明符(第 7.1.5.3 节):

template< typename T > struct s;
template< typename T > s< int > *f() {}

template<> struct u *f< char >(); // struct u is declared
u *p = 0; // see, we can use its name now.
template<> struct s< int > *f< int >(); // s<int> declared but not specialized
template struct s< int > *f< long >(); // s<int> declared but not instantiated

据我所知,标准对于指定哪个声明的名称是专门的名称是模糊的。该语言确实暗示每个这样的声明仅适用于一个模板:§14.7.2/2

如果显式实例化是针对类、函数或成员模板特化......</p>

和§14.7.3/2

应在模板所属的命名空间中声明显式特化……</p>

如果声明器还指定了合法的实例化/特化,则解决此问题的唯一方法是忽略类型声明。

切入正题,问题中的示例在声明器中指定了非法的特化,然后期望编译器回溯并专门化该类型。鉴于在 §14.7.2/1 和 §14.7.3/1 中明确列出了允许执行哪些特化和声明,抱怨不是函数模板、成员函数模板、静态数据成员似乎template<> struct t< int > {} r;r合理类模板等

于 2011-06-20T18:30:52.393 回答