模板、数组和常量表达式

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 变量时才会出现问题。