为什么这不是一个恒定的表达?

Chr*_*s_F 20 c++ templates constexpr c++11 c++14

在这个简单的例子中,test2即使test1成功也无法编译,我不明白为什么会这样.如果arr[i]适用于标记函数的返回值,constexpr那么为什么它不能用作非类型模板参数?

template<char c>
struct t
{ 
    static const char value = c;
};

template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i)
{
    return arr[i];
}

template <unsigned N>
constexpr char test2(const char (&arr)[N], unsigned i)
{
    return t<arr[i]>::value;
}

int main()
{
   char a = test1("Test", 0); //Compiles OK
   char b = test2("Test", 0); //error: non-type template argument 
                              //is not a constant expression
}
Run Code Online (Sandbox Code Playgroud)

编辑:这没有区别:

template<char c>
struct t
{ 
    static const char value = c;
};

template <unsigned N>
constexpr char test1(const char (&arr)[N])
{
    return arr[0];
}

template <unsigned N>
constexpr char test2(const char (&arr)[N])
{
    return t<arr[0]>::value;
}

int main()
{
   char a = test1("Test"); //Compiles OK
   char b = test2("Test"); //error: non-type template argument 
                           //is not a constant expression
}
Run Code Online (Sandbox Code Playgroud)

Tem*_*Rex 23

简答:没有constexpr函数参数C++11/14.

更长的答案:在test1(),如果i不是编译时常量,该函数仍然可以在运行时使用.但是test2(),编译器无法知道它是否i是编译时常量,但是编译时需要它.

例如,以下代码test1将编译

int i = 0;    
char a = test1("Test", i); // OK, runtime invocation of test1()

constexpr int i = 0;
constexpr char a = test1("Test", i); // also OK, compile time invocation of test1()
Run Code Online (Sandbox Code Playgroud)

让我们简单的test2()

constexpr char test3(unsigned i)
{
    return t<i>::value;
}
Run Code Online (Sandbox Code Playgroud)

这不会编译,test3(0)因为在内部test3(),无法证明这i是一个无条件的编译时表达式.您需要constexpr能够表达的函数参数.

从标准引用

5.19常量表达式[expr.const]

2条件表达式e是核心常量表达式,除非根据抽象机器(1.9)的规则评估e将评估以下表达式之一:

- 一个id-expression,引用引用类型的变量或数据成员,除非引用具有先前的初始化并且
- 或者使用常量表达式初始化或

- 它是一个对象的非静态数据成员,其生命周期始于e的评估范围内;

本节包含与您的问题对应的以下代码示例:

constexpr int f1(int k) {
    constexpr int x = k; // error: x is not initialized by a
                         // constant expression because lifetime of k
                         // began outside the initializer of x
    return x;
}
Run Code Online (Sandbox Code Playgroud)

因为x在上面的示例中不是常量表达式,这意味着您无法使用其中一个xk内部实例化模板f1.


Use*_*ess 7

这里有什么误解constexpr.这表明,一个函数必须在编译时合适的参数可求,但它并不能去除的需求仍然在一般情况下进行编译.

我们来看第一个版本:

template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
    return arr[i];
}
Run Code Online (Sandbox Code Playgroud)

现在,这显然是一个编译时评估:

enum { CompileTimeConstant = test1("Test", 0) };
Run Code Online (Sandbox Code Playgroud)

你的例子可能是,但这是一个优化器/ QoI问题:

char MayBeCompileTimeConstant = test1("Test", 0);
Run Code Online (Sandbox Code Playgroud)

这个例子显然不是,但仍然需要可评估

char arr[10];
int i;
std::cin >> i;
std::cin >> arr;
char b = test1(arr, i);
std::cout << "'" << arr << "'[" << i << "] = " << b << '\n';
Run Code Online (Sandbox Code Playgroud)

由于test2无法编译为最后一种情况,它根本无法编译.(请注意,我并不是说代码是好的).