5.19 / 3定义了一个整数常量表达式和一个转换后的常量表达式:
积分常量表达式是整数或。的表达式 unscoped枚举类型,隐式转换为prvalue,其中 转换后的表达式是核心常量表达式。 [注意:这样 表达式可以用作数组边界(8.3.4,5.3.4),作为位字段 长度(9.6),如果基础类型是枚举器初始值设定项 不固定(7.2),并作为路线(7.6.2)。 -end note] 已转换 类型
T
的常量表达式是一个隐含的表达式 转换为T
类型的prvalue,转换后的表达式为 核心常量表达式和隐式转换序列 仅包含用户定义的转化,左值到右值的转化 (4.1),整体促销(4.5)和积分转换(4.7)其他 而不是缩小转换率(8.5.4)。 [注意:这样的表达可能是 在new
表达式(5.3.4)中用作case
表达式(6.4.2),as 如果基础类型是固定的(7.2),则为枚举器初始值设定项 数组边界(8.3.4),以及整数或枚举非类型模板 论证(14.3)。 - 后注]
也许我错过了一些东西,但我的第一印象是每个整数常量表达式都是转换的常量表达式。
修改
而且我也相信这一段中有错误:
而不是:
A converted constant expression of type T is an expression, implicitly converted to a prvalue of type T, ...
它应该是:
A converted constant expression of type T is an expression, implicitly converted to a prvalue of an integral type, ...
此更改允许编译以下代码:
#include <iostream>
struct A { operator int() { return 5; } } a;
int main() {
int b[a]{ 0, 1, 2, 3, 4 };
std::cout << b[4] << '\n';
}
声明a
中的int b[a]{ 0, 1, 2, 3, 4};
是转换的常量表达式,类型为A
,隐式转换为整数类型的prvalue({{1} })转换后的表达式int
是核心常量表达式,隐式转换序列仅包含用户定义的转换。
答案 0 :(得分:4)
注意:此答案基于最新的标准草案,现在称为N4567。指出了它与C ++ 11/14标准之间的一些区别。
整数常量表达式和转换常量表达式在涉及类类型时是不同的。在C ++ 98/03中,当这里不能使用类类型时(因为那时没有constexpr
个转换函数),确实没有像{em>转换常量表达式{{{ 1}}
对于整数常量表达式,目标类型未知。但对于转换的T
类型的常量表达式,目标类型已知为T
,而T
不一定是整数或未范围的枚举类型< SUP> 1
因此,为了编译整型常量表达式,编译器首先需要确定目标类型是什么。如果表达式具有整数或未整合的枚举类型,那么显然目标类型只是表达式的类型。否则,如果表达式具有文字类类型(让我们调用此类型T
),则使用以下过程 2 :
编译器检查E
3 中的所有非显式转换函数。假设这些函数的结果类型形成集合E
。如果S
只包含一个整数或无范围的枚举类型(参考修饰符被删除,S
和const
限定符被忽略:volatile
在此被视为const volatile int&
进程),然后目标类型就是那种类型。否则,确定失败。
(重要的是要注意,在上述过程中,不检查转换函数模板。)
因此,例如,如果类类型有两个转换函数,一个是int
而另一个是constexpr operator int
,则此类型不能用于积分常量表达式(目标类型是不可判定的)。但是,此类型可用于转换的constexpr operator long
类型的常量表达式或转换后的常量表达式int
。
在确定目标类型long
之后,应用重载决策来查找最合适的转换函数或函数模板,然后调用选择的转换函数(必须为D
)才能生成值constexpr
的值。 - 这部分或多或少与转换的D
类型的常量表达式相同。
在以下示例中,D
是有效的整数常量表达式,但是类型为Var{}
的转换常量表达式无效(示例的灵感来自this question)。
std::size_t
N4567 5.20 [expr.const] p7
如果在需要整数常量表达式的上下文中使用了文字类类型的表达式, 然后,该表达式在上下文中被隐式转换(第4条)为整数或无范围的枚举 类型和选定的转换函数应为
class Var { public: constexpr operator int () { return 42; } template <typename T> constexpr operator T () = delete; }; enum { x = Var{} // the initializer of `x` is expected to be an // integral constant expression // x has value 42 }; int t[ Var{} ]; // the array bound is expected to be a // converted constant expression of type std::size_t // this declaration is ill-formed
。
N4567 4 [conv] p5
某些语言结构需要转换为具有适合于构造的特定类型集之一的值。在这样的上下文中出现的类类型
constexpr
的表达式e
被称为在上下文中被隐式转换为到指定类型E
,并且如果和仅当T
可以隐式转换为确定如下的类型e
时:T
将搜索返回类型为 cv 的非显式转换函数E
或 cvT
的引用,以便上下文允许T
。应该只有一个T
。
答案 1 :(得分:0)
在讨论了Jerry Coffin和cpplearner提供的答案之后,让我建议重写那些该死的规则,如下:
[expr.const] 5.20 \ 3(已修改)
整型常量表达式是整数或未整数枚举类型的表达式,它隐式转换为相同类型的prvalue核心常量表达式,以便隐式转换序列仅包含左值 - -rvalue conversion。
[expr.const] 5.20 \ 4(已修改)
T类型的转换常量表达式是any的表达式 type,隐式转换为T类型的常量表达式 这样隐式转换序列只包含:
- 用户定义的转化
- 左值到右值的转化,
- 数组到指针的转换,
- 功能到指针的转换,
- 资格转换,
- 整体促销,
- 除了缩小转化次数之外的整数转换,
- 来自
的空指针转换std::nullptr_t
,- 来自
的空成员指针转换std::nullptr_t
和- 函数指针转换,
并且引用绑定(如果有)直接绑定。 [注意:这样 表达式可以在
new
表达式中使用,作为case表达式,如 枚举器初始值设定项,如果基础类型是固定的,则为数组 bounds和非类型模板参数。 - 结束说明]
现在区别很明显,呃?还应该提醒一下,根据5.20 \ 7;在一些情况下,可以使用文字类型的表达式代替整数常量表达式。