我了解以下行为是违法的:
template<typename T>
struct will_get_explicitly_specialized {
using type = void;
};
template<typename T>
struct ordinary_template {
using type = typename will_get_explicitly_specialized<T>::type;
};
ordinary_template<int> x;
template<>
struct will_get_explicitly_specialized<int> {
using type = int;
};
这将(希望如此,因为我相信这不是必需的)生成如下错误:
<source>:16:8: error: specialization of 'will_get_explicitly_specialized<int>' after instantiation
16 | struct will_get_explicitly_specialized<int> {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:16:8: error: redefinition of 'struct will_get_explicitly_specialized<int>'
<source>:4:8: note: previous definition of 'struct will_get_explicitly_specialized<int>'
4 | struct will_get_explicitly_specialized {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 1
这符合我的理解,即
will_get_explicitly_specialized
的所有显式特化都需要出现在 will_get_explicitly_specialized
的任何隐式实例化之前,并且 ordinary_template<int> x
的声明必然会导致 ordinary_template<int>
的实例化,而这又似乎需要隐式实例化由于 will_get_explicitly_specialized<int>
声明,using type =
。
有趣的是,代码中该位置的顶级
using
语句不会引发诊断(在相同环境中):
template<typename T>
struct will_get_explicitly_specialized {
using type = void;
};
template<typename T>
struct ordinary_template {
using type = typename will_get_explicitly_specialized<T>::type;
};
using ot_int = ordinary_template<int>;
template<>
struct will_get_explicitly_specialized<int> {
using type = int;
};
ot_int x;
我想知道这是否仍然是非法的(但也许没有发出诊断并且不需要诊断),或者这种
using
语句是否与 ordinary_template
中的语句有所不同,因此它不算数导致 will_get_explicitly_specialized
的隐式实例化。
无论哪种情况,什么语言可以清楚地表明
using
语句中模板的特化是否/何时导致隐式实例化?
直觉上感觉应该可以在所有专业化之前说
using ot_int = ordinary_template<int>
,因为直到你以某种方式实际使用ot_int
之前,没有任何事情真正发生,以至于ordinary_template<int>
需要存在。但当然,仅仅因为感觉是这样,并不代表它就是真的!
这将(希望如此,因为我相信这不是必需的)生成如下错误:
从技术上讲,第一个程序是根据 [temp.expl.spec]/7 的 IFNDR(格式错误,无需诊断),因为没有声明可从
will_get_explicitly_specialized<int>
访问 ordinary_template<int> x;
的显式专业化,但是这会导致相同专业化的隐式实例化。
因此从技术上讲不需要编译器来诊断问题。该程序对编译器没有任何要求。
简单地使用 template-id 命名专业化不会导致它被隐式实例化。仅当类类型在使用时要求完整或其完整性会影响程序语义时,类模板特化才会隐式实例化。
在变量的定义中,例如
ordinary_template<int> x;
或
ot_int x;
变量的类型必须始终完整。这意味着在这两种情况下
ordinary_template<int>
必须在此时隐式实例化(如果它尚未事先实例化)。
但是,简单地声明类型别名并不要求类型完整,并且如果类型不完整,声明也不具有任何不同的语义。
因此,简单地为类模板特化添加别名永远不会导致它被隐式实例化。因此,您的第二个程序不会违反上述规则,并且格式良好,具有定义的行为(除了缺少
main
之外)。根据显式专业化的要求,ot_int::type
将是 int
。