模板、数组和常量表达式
Templates, arrays and constant expressions
考虑以下代码:
template<char>
struct S { };
template<int N>
constexpr auto f(const char (&ref) [N]) {
return S<ref[0]>{};
}
int main() {
constexpr auto v = f("foo");
(void)v;
}
它不编译,因为 ref[0]
不是常量表达式。
无论如何,下面的代码编译得很好:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return ref[0];
}
int main() {
constexpr auto v = f("foo");
(void)v;
}
他们是否应该出于或多或少相同的原因编译或失败?
从 [expr.const] 我们有:
A conditional-expression e
is a core constant expression unless the evaluation of e
[...] would evaluate one of the following expressions:
[...]
- an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
- it is initialized with a constant expression or
- its lifetime began within the evaluation of e
;
无论如何,在这种情况下,它是用常量表达式初始化的并且生命周期与e
相同,因此该规则不适用。
我的推理有什么问题?
作为附带问题,我会问是否可以使用这样的数组或其中的一部分作为模板参数。
第一个示例不应编译,因为您不能拥有仅编译时的 constexpr 函数(或在编译时重载,如 D 的 __cfte
)。
根据这个推理,如果您在运行时调用第一个示例的 f
,它的 return 类型会是什么?
关于附带问题:Boost Hana,尽管仅支持最新标准,但仅将字符串文字用于运行时内容,因此可能无法实现。
这个:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return S<ref[0]>{};
}
格式错误,因为根据 [temp.arg.nontype]:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of
the type of the template-parameter.
来自[expr.const]:
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the
abstract machine (1.9), would evaluate one of the following expressions: [...]
(2.7) — an lvalue-to-rvalue conversion (4.1) unless it is applied to
(2.7.1) — a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const
object with a preceding initialization, initialized with a constant expression, or
(2.7.2) — a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
(2.7.3) — a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to
a non-mutable sub-object of such an object, or
(2.7.4) — a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within
the evaluation of e;
ref[0]
需要左值到右值的转换,并且 none 这些子项目符号适用。请注意,ref
不是字符串文字,因此 2.7.2 不适用,也不是用 constexpr
定义的,因为它是函数参数,我们没有该功能。
我们基本上需要能够将字符串文字 作为文字 传递,但目前尚不存在。
另一个例子:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return ref[0];
}
没有所需的转换常量表达式 - 由模板非类型参数引入的常量表达式。这段代码很好,只有在您尝试使用非 constexpr
数组值初始化 constexpr
变量时才会出现问题。
考虑以下代码:
template<char>
struct S { };
template<int N>
constexpr auto f(const char (&ref) [N]) {
return S<ref[0]>{};
}
int main() {
constexpr auto v = f("foo");
(void)v;
}
它不编译,因为 ref[0]
不是常量表达式。
无论如何,下面的代码编译得很好:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return ref[0];
}
int main() {
constexpr auto v = f("foo");
(void)v;
}
他们是否应该出于或多或少相同的原因编译或失败?
从 [expr.const] 我们有:
A conditional-expression
e
is a core constant expression unless the evaluation ofe
[...] would evaluate one of the following expressions:
[...]
- an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
- it is initialized with a constant expression or
- its lifetime began within the evaluation ofe
;
无论如何,在这种情况下,它是用常量表达式初始化的并且生命周期与e
相同,因此该规则不适用。
我的推理有什么问题?
作为附带问题,我会问是否可以使用这样的数组或其中的一部分作为模板参数。
第一个示例不应编译,因为您不能拥有仅编译时的 constexpr 函数(或在编译时重载,如 D 的 __cfte
)。
根据这个推理,如果您在运行时调用第一个示例的 f
,它的 return 类型会是什么?
关于附带问题:Boost Hana,尽管仅支持最新标准,但仅将字符串文字用于运行时内容,因此可能无法实现。
这个:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return S<ref[0]>{};
}
格式错误,因为根据 [temp.arg.nontype]:
A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter.
来自[expr.const]:
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions: [...]
(2.7) — an lvalue-to-rvalue conversion (4.1) unless it is applied to
(2.7.1) — a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
(2.7.2) — a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
(2.7.3) — a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or
(2.7.4) — a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;
ref[0]
需要左值到右值的转换,并且 none 这些子项目符号适用。请注意,ref
不是字符串文字,因此 2.7.2 不适用,也不是用 constexpr
定义的,因为它是函数参数,我们没有该功能。
我们基本上需要能够将字符串文字 作为文字 传递,但目前尚不存在。
另一个例子:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return ref[0];
}
没有所需的转换常量表达式 - 由模板非类型参数引入的常量表达式。这段代码很好,只有在您尝试使用非 constexpr
数组值初始化 constexpr
变量时才会出现问题。