N4527 14.6 [temp.res] / p8
如果立即假设实例化模板 由于不依赖于模板参数的构造,其定义之后将是不正确的, 该计划格式不正确;无需诊断。如果解释这样的结构在 假设实例化与任何实际的相应结构的解释不同 实例化模板,程序形成不良;无需诊断。 [注意:这可能发生 在包括以下情况的情况下:
(8.1) - 非依赖名称中使用的类型在定义模板时是不完整的但是 在执行实例化时完成,或
(8.2) - 实例化使用默认参数或默认模板参数,该参数尚未定义 模板定义的位置或
(8.3) - 模板实例化中的常量表达式评估(5.20)使用
(8.3.1) - 整数或无范围枚举类型的const对象的值或
(8.3.2) - constexpr对象的值或
(8.3.3) - 参考值或
(8.3.4) - constexpr函数的定义,
并且在定义模板时未定义该实体,或
那么,这些代码是否格式错误?
代码1:
extern double b;
template<class T>
void f(T=b){}
void g(){
f<double>();//ill-formed or not?
}
double b = 0;
void h(){
f<double>();//ill-formed or not?
}
代码2:
//translation 1
extern double b;
template<class T>
void f(T=b){}
void g(){
f<double>();//ill-formed or not?
}
//translation 2
double b = 0;
Issue1850 Differences between definition context and point of instantiation
模板中非依赖引用所引用的实体的各种特征可以在定义上下文与该模板的特化实例化点之间发生变化。这些包括初始化(它影响对象是否可以在常量表达式中使用),函数和模板默认参数以及类型的完整性。关于在定义上下文中还是在实例化时检查这些是否存在实现差异。如果这种参考的有效性在两种情况之间发生变化,可能需要一条规则来使其形成不良,不需要诊断。
您能否向我展示更多关于两个上下文之间非依赖名称的特征如何不同的例子?通常约为8.2和8.3.1
答案 0 :(得分:5)
以下是一个例子:
extern const int b;
template<int, int>
void f(int);
template<int, const int &>
void f(long);
template<class>
void g() {
f<0, b>(0);
}
// #1
extern const int b = 0;
int main(){
g<int>();
}
// #2
#1的假设实例化会调用void f<0, b>(long)
,因为b
此时不是一个常量表达式,因此(int)
会超出SFINAE。 #2(这是g<int>
的实例化点)的实例化将调用void f<0, 0>(int)
,因为那时b
是一个常量表达式,(int)
重载是可行的,赢得超载决议。
Clang and GCC will in fact call different f
s with this code.