请考虑以下代码:
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]我们得到了:
条件表达式
的评估e
是核心常量表达式,除非e
[...]的评估将评估以下表达式之一:
[...]
- 一个id-expression,引用引用类型的变量或数据成员,除非引用具有先前的初始化和任何
- 用常量表达式初始化或
- 它的生命周期始于e
;
无论如何,在这种情况下,它使用常量表达式和进行初始化,生命周期与e
相同,因此规则不适用。
我的推理出了什么问题?
作为一个附带问题,我会问是否可以使用这样的数组或其中的一部分作为模板参数。
答案 0 :(得分:1)
此:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return S<ref[0]>{};
}
是不正确的,因为根据[temp.arg.nontype]:
非类型模板参数的 template-argument 应为转换后的常量表达式(5.20) 模板参数的类型。
和[expr.const]:
条件表达式 e是一个核心常量表达式,除非对e的评估,遵循规则 抽象机器(1.9),将评估以下表达式之一:[...]
(2.7) - 左值 - 右值转换(4.1),除非它适用于
(2.7.1) - 整数或枚举类型的非易失性glvalue,指的是完整的非易失性const 具有先前初始化的对象,使用常量表达式初始化,或者 (2.7.2) - 一个非易失性glvalue,引用字符串文字的子对象(2.13.5)或
(2.7.3) - 一个非易失性glvalue,指的是用constexpr定义的非易失性对象,或者指的是 这种对象的不可变子对象,或
(2.7.4) - 文字类型的非易失性glvalue,引用其生命周期开始于其中的非易失性对象 评估e;
ref[0]
需要左值到右值的转换,并且这些子项目都不适用。请注意ref
不是字符串文字,因此2.7.2不适用,也不用constexpr
定义,因为它是函数参数,我们没有这个功能。
我们基本上需要能够将字符串文字作为文字传递,但尚不存在。
另一个例子:
template<int N>
constexpr auto f(const char (&ref) [N]) {
return ref[0];
}
没有所需的转换常量表达式 - 一个是由模板非类型参数引入的。此代码很好,如果您尝试使用非constexpr
数组值初始化constexpr
变量,则只会出现问题。
答案 1 :(得分:0)
第一个例子不应该编译,因为你不能只有编译时的constexpr函数(或者编译时的重载,比如D __cfte
)。
根据这个推理,如果你在运行时调用第一个例子的f
,它的返回类型是什么?
至于附带问题:Boost Hana尽管只支持最新标准,但只使用字符串文字作为运行时内容,因此可能无法实现。