C ++中定义上下文和实例化点之间非依赖性构造的解释差异

sta*_*cpp 5 c++ templates token-name-resolution language-lawyer

N4527 14.6 [温度] / 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?
}
Run Code Online (Sandbox Code Playgroud)

代码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;
Run Code Online (Sandbox Code Playgroud)

Issue1850定义上下文和实例化点之间的区别

模板中非依赖引用所引用的实体的各种特性可以在定义上下文和该模板的专门化实例化点之间改变。其中包括初始化(影响是否可以在常量表达式中使用对象),函数和模板默认参数,以及类型的完整性。关于是在定义上下文中还是在实例化点进行检查,存在实现上的分歧。如果这样的引用的有效性在两个上下文之间发生变化,则可能需要一个规则来使其格式错误,而无需诊断。

您能否向我展示更多有关两个上下文之间非依赖名称的特征有何不同的示例?通常约为8.2和8.3.1

T.C*_*.C. 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
Run Code Online (Sandbox Code Playgroud)

在#1处的假设实例化将调用void f<0, b>(long),因为此时b不是常量表达式,所以(int)重载SFINAE消失了。#2处的实例化(这是的实例化点g<int>)将调用void f<0, 0>(int),因为到那时b是一个常量表达式,(int)重载是可行的,并赢得了重载解决方案。

Clang和GCC实际上将f使用此代码调用不同的。