N4527 5.20 [expr.const] p5
常量表达式是glvalue核心常量表达式,其值指的是一个实体,它是常量表达式的允许结果(如下定义),或者是一个prvalue核心常量表达式,其值是一个对象,对于该对象及其子对象:
- 引用类型的每个非静态数据成员是指一个实体,它是一个常量表达式的允许结果,和
- 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象的结尾的地址(5.7),函数的地址或空指针值.
如果实体是具有静态存储持续时间的对象,则该实体是常量表达式的允许结果,该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是函数.
void foo(){
int a = 1;
int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
switch(1){
case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
;
}
}
Run Code Online (Sandbox Code Playgroud)
是a || 1一个不变的表达?
N4527 5.20 [expr.const] p2
条件表达式e是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一:
(2.7) - 左值 - 右值转换(4.1),除非适用于
(2.7.1) - 整数或枚举类型的非易失性glvalue,它引用具有前面初始化的完整非易失性const对象,用常量表达式初始化,或者
(2.7.2) - 一个非易失性glvalue,引用字符串文字的子对象(2.13.5),或者
(2.7.3) - 一个非易失性glvalue,引用用constexpr定义的非易失性对象,或引用这种对象的不可变子对象,或者
(2.7.4) - …
struct S{
int a[3] = {1,2,3};
};
S&& f(){return S();}
&f().a; //[Error] taking address of xvalue (rvalue reference)
&f().a[0]; //ok in GCC 5.1.0 and Clang 3.6.0
S s;
&static_cast<S&&>(s).a; //[Error] taking address of xvalue (rvalue reference)
&static_cast<S&&>(s).a[0]; //ok in GCC 5.1.0 and Clang 3.6.0
Run Code Online (Sandbox Code Playgroud)
5.7表达式是xvalue,如果它是:
(7.1) - 调用函数的结果,无论是隐式还是显式,其返回类型是对象类型的右值引用,
(7.2) - 对对象类型的右值引用的强制转换,
(7.3) - 一个类成员访问表达式,指定非引用类型的非静态数据成员,其中对象表达式是xvalue,或者
(7.4) - a.*指向成员的表达式,其中第一个操作数是xvalue,第二个操作数是指向数据成员的指针.
5.2.1订阅后缀表达式后跟方括号中的表达式是后缀表达式.其中一个表达式的类型为"array of
T"或"指向T",另一个表达式应具有未映射的枚举或整数类型.结果是"T" 类型.类型"T"应该是完全定义的对象类型.表达式E1[E2](根据定义)与*((E1)+(E2))<<*t[注意:有关数组的详细信息,请参见5.3和5.7*以及+和8.3.4的详细信息).-end note],除了在数组操作数的情况下,如果该操作数是左值,则结果为左值,否则为x值.
那么,是f().a[0] …
N4527 14.5.5.1 [temp.class.spec.match]
2如果可以从实际模板参数列表推导出部分特化的模板参数,则部分特化匹配给定的实际模板参数列表.
Run Code Online (Sandbox Code Playgroud)template<class T1, class T2, int I> class A { }; // #1 template<class T, int I> class A<T, T*, I> { }; // #2 template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3 template<class T> class A<int, T*, 5> { }; // #4 template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5 A<int, int, 1> a1; // uses #1 A<int, int*, 1> a2; // uses #2, …
struct A { A(int);};
struct B { explicit B(A); B(const B&);};
B b({0});
Run Code Online (Sandbox Code Playgroud)
gcc 5.1.0给出了错误
/dev/fd/63:3:8: error: call of overloaded 'B(<brace-enclosed initializer list>)'
is ambiguous
/dev/fd/63:3:8: note: candidates are:
/dev/fd/63:2:27: note: B::B(const B&)
/dev/fd/63:2:21: note: B::B(A)
Run Code Online (Sandbox Code Playgroud)
而clang 3.6.0成功了.
哪一个是对的?为什么?
对于gcc 5.1.0:http://melpon.org/wandbox/permlink/pVe9eyXgu26NEX6X
对于clang 3.6.0:http://melpon.org/wandbox/permlink/WOi1md2dc519SPW0
这可能类似于直接列表初始化编译成功,但正常的直接初始化失败,为什么?哪个gcc和clang得到相同的结果.
但这是一个不同的问题.B(A)在这里是明确的.gcc和clang得到不同的结果.
N4527 7.1.5 [dcl.constexpr] p9
对象声明中使用的constexpr说明符将对象声明为const.这样的对象应具有文字类型并应初始化.如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式(5.20).否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式.
5.20 [expr.const] P5
常量表达式是glvalue核心常量表达式,其值指的是一个实体,它是常量表达式的允许结果(如下定义),或者是一个prvalue核心常量表达式,其值是一个对象,对于该对象及其子对象:
- 引用类型的每个非静态数据成员是指一个实体,它是一个常量表达式的允许结果,和
- 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象的结尾的地址(5.7),函数的地址或空指针值.
如果实体是具有静态存储持续时间的对象,则该实体是常量表达式的允许结果,该对象不是临时对象,或者是其值满足上述约束的临时对象,或者它是函数.
void foo(){
constexpr const int &a = 1;//error
constexpr static const int &b = 1;//ok in gcc 5.1.0 and clang 3.8.0
}
Run Code Online (Sandbox Code Playgroud)
问题:为什么constexpr const int &a = 1;块范围失败?
template<class ... T>
struct S{
template<int>
struct A{};
template<T...>
struct B{};
template<template<T...> class>
struct C{};
};
S<int>::C<S<int>::B> s1;
S<int>::C<S<int>::A> s2;//gcc5.1.0 fails, clang3.6.0 succeeds
int main(){}
Run Code Online (Sandbox Code Playgroud)
你可以在这里测试http://melpon.org/wandbox/permlink/hhy70gO9LMjLq9nU
哪一个是正确的,gcc还是clang?
在N4296中,3.2 [basic.def.odr] p3:
一种可变
x为潜在评估表达式出现的名字ex被ODR-使用ex,除非将所述左值到右值转换到x产率的常量表达式不调用任何非平凡函数,并且如果x是一个对象,ex是的一个元素表达式的潜在结果集e,其中应用了左值到右值的转换e,或者e是丢弃值表达式.
如何解释这一段?我找到了两个解释.
1从这里" 试图理解[basic.def.odr]/2 in C++ 14(N4140) "
让我们把它分成几步:在表达式"ex"中出现变量"x"构成一个odr-use,除非:
- 要么
ex没有潜在的评估,要么- 必须满足以下所有条件:
- "应用左值到右值的转换
x产生一个不调用任何非平凡函数的常量表达式" 和- "
ex是表达式的潜在结果集合的一个元素e", 并且以下任何一个成立:
- " 要么将左值到右值转换应用于
e"- " 或者
e是一种废弃的价值表达"
和cppreference中的2个http://en.cppreference.com/w/cpp/language/definition
除非满足以下任何条件,否则
x潜在评估表达式中的变量将ex使用odr :
应用左值到右值的转换
x产生一个不调用非平凡函数的常量表达式
x是一个对象,ex是较大表达式的潜在结果之一e,其中较大的表达式是丢弃值表达式或左值到右值转换
大约两个规则的第一个答案是和,另一个是任何.哪一个是对的?
请将规则拆分为步骤来解释此代码:
struct S …Run Code Online (Sandbox Code Playgroud) 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)
模板中非依赖引用所引用的实体的各种特性可以在定义上下文和该模板的专门化实例化点之间改变。其中包括初始化(影响是否可以在常量表达式中使用对象),函数和模板默认参数,以及类型的完整性。关于是在定义上下文中还是在实例化点进行检查,存在实现上的分歧。如果这样的引用的有效性在两个上下文之间发生变化,则可能需要一个规则来使其格式错误,而无需诊断。
您能否向我展示更多有关两个上下文之间非依赖名称的特征有何不同的示例?通常约为8.2和8.3.1