类模板显式特化还可以声明其他东西吗?

Pot*_*ter 11 c++ templates explicit-specialization

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

template< typename > struct t;

template<> struct t< int > {} r; // Bad declarator! Don't pee on the carpet!
Run Code Online (Sandbox Code Playgroud)

(编辑:以上编译,但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.
Run Code Online (Sandbox Code Playgroud)

我倾向于同意海湾合作委员会的解释,尽管可能是胡说八道.不幸的是,它可能会抑制其检测缺失的分号的能力.请允许声明者的数量正好为零!

Jam*_*nze 13

几点:首先,显式特化不在模板和类之间的下层区域; 明确的专业化是一个阶级,时期.唯一的关系是模板(有趣的名称除外)是,如果要在特化类型上实例化模板,它将被用来代替模板实例化.

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

struct S {} s, *p;
Run Code Online (Sandbox Code Playgroud)

是合法的,

template<> struct T<int> {} s, *p;
Run Code Online (Sandbox Code Playgroud)

应该也是.(我会反对允许,但是那列火车已经离开了火车站,而且由于C允许第一辆火车,我们坚持使用它.)

否则,§14/ 3中的陈述有点无关紧要.函数模板必须只有一个声明符,而一个类模板必须为零; 没有必要试图让他们在一些"最多一个"gobbledygook中兼顾它们.(如果我是从头开始设计语言,我不允许在声明中定义类或枚举类型的任何声明器.但是,再说一次,它已经太迟了.)

我同意这是一个麻烦:

template<> struct T<int> {};    //  Requires a ';'
template<> void f<int>() {}     //  ';' forbidden
Run Code Online (Sandbox Code Playgroud)

(在函数定义之后,至少C++ 11将允许使用分号.)

  • @Potatoswatter不需要道歉.我能理解你的观点.关于我的理解:我一直都知道类模板的实例化(无论是否显式)是一个类,而函数模板的实例化是一个函数.但是现在我在标准中寻找它,我找不到这种效果的陈述; 也许是第一句话:"模板定义了一个类或函数族"(所以每个实例都是一个家族的成员,即一个类或一个函数)? (2认同)

Pot*_*ter 1

显式专业化和显式实例化不声明模板。他们声明一个template-id来引用一个专门化,它是一个类。

\n\n

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

\n\n

考虑这些示例,这些示例无偿但合法地使用了详细类型说明符 (\xc2\xa77.1.5.3):

\n\n
template< typename T > struct s;\ntemplate< typename T > s< int > *f() {}\n\ntemplate<> struct u *f< char >(); // struct u is declared\nu *p = 0; // see, we can use its name now.\ntemplate<> struct s< int > *f< int >(); // s<int> declared but not specialized\ntemplate struct s< int > *f< long >(); // s<int> declared but not instantiated\n
Run Code Online (Sandbox Code Playgroud)\n\n

据我所知,该标准对于指定哪个声明的名称是专门的名称是模糊的。该语言确实微弱地暗示每个此类声明仅适用于一个模板:\xc2\xa714.7.2/2

\n\n
\n

如果显式实例化是针对类、函数或成员模板特化\xe2\x80\xa6

\n
\n\n

和 \xc2\xa714.7.3/2

\n\n
\n

应在模板所属的命名空间中声明显式特化\xe2\x80\xa6

\n
\n\n

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

\n\n

言归正传,问题中的示例在声明符中指定了非法的专业化,然后期望编译器回溯并专门化该类型。考虑到 \xc2\xa714.7.2/1 和 \xc2\xa714.7.3/1 中允许执行的特化和声明的明确列表,抱怨这template<> struct t< int > {} r;不是r函数模板、成员函数模板似乎更合理,类模板的静态数据成员等。

\n