模板,数组和常量表达式

时间:2016-10-17 14:01:38

标签: c++ templates constant-expression template-deduction

请考虑以下代码:

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相同,因此规则不适用。

我的推理出了什么问题?

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

2 个答案:

答案 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尽管只支持最新标准,但只使用字符串文字作为运行时内容,因此可能无法实现。