模板、数组和常量表达式

Templates, arrays and constant expressions

本文关键字:常量 表达式 数组 模板      更新时间:2023-10-16

考虑以下代码:

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。我们有:

条件表达式e核心常数表达式,除非e的求值[…]]将计算下列表达式之一:
[…]
- id表达式,指向引用类型的变量或数据成员,除非引用之前有初始化并且
   -使用常量表达式或
初始化    -其生命周期开始于e的评估;

无论如何,在这种情况下,它是用常量表达式初始化的,的生存期与e相同,因此规则不适用。

我的推理有什么问题?

作为附带问题,我想问是否可以使用这样一个数组或它的一部分作为模板参数

This:

template<int N>
constexpr auto f(const char (&ref) [N]) {
    return S<ref[0]>{};
}

是病态的,因为根据[temp.arg.nontype]:

非类型模板形参模板实参必须是的转换常量表达式(5.20)模板参数的类型。

and from [expr.const]:

A 条件表达式 e是一个核心常量表达式,除非对e求值,遵循抽象机器(1.9)将计算下列表达式之一:[…]
(2.7) -左值到右值的转换(4.1),除非它应用于
(2.7.1) -指向完整的非易失性const的整型或枚举类型的非易失性glvalue对象,用常量表达式初始化,或
(2.7.2) -指向字符串字面值(2.13.5)的子对象或
的非易失性全局值(2.7.3) -一个非易失性的glvalue,它指向用constexpr定义的非易失性对象,或者指向该对象的不可变子对象,或
(2.7.4) -一个文字类型的非易失性全局值,它指向一个生命周期开始于

的求值

ref[0]需要左值到右值的转换,并且这些子符号都不适用。注意,ref不是字符串字面量,所以2.7.2不适用,它也不是用constexpr定义的,因为它是一个函数参数,我们没有这个功能。

我们基本上需要将字符串字面值作为字面值传递的能力,这种能力目前还不存在。


另一个例子:

template<int N>
constexpr auto f(const char (&ref) [N]) {
    return ref[0];
}

没有所需的转换常量表达式——该表达式是由模板非类型参数引入的。这段代码很好,只有当您试图用非constexpr数组值初始化constexpr变量时才会出现问题。

第一个示例不应该编译,因为您不能使用仅编译时的constexpr函数(或像D的__cfte那样重载编译时)。

根据这个推理,如果你在运行时调用第一个例子的f,它的返回类型是什么?

至于旁边的问题:Boost Hana,尽管只支持最新的标准,只使用字符串文字运行时的东西,所以这可能是不可能的。