C++ 为什么这不是一个常量表达式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24580714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:46:10  来源:igfitidea点击:

Why is this not a constant expression?

c++templatesc++11constexprc++14

提问by Chris_F

In this trivial example, test2fails to compile even though test1succeeds, and I don't see why that is the case. If arr[i]is suitable for a return value from a function marked constexprthen why can it not be used as a non-type template argument?

在这个简单的例子中,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
}

Edit: This makes no difference:

编辑:这没有区别:

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
}

回答by TemplateRex

Short answer: there are no constexprfunction parameters in C++11/14.

简短的回答:有没有constexpr在功能参数C++11/14

Longer answer: in test1(), if iis not a compile-time constant, the function is still usable at run-time. But in test2(), it cannot be known to the compiler whether iis a compile-time constant, and yet it is required for the function to compile.

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

E.g. the following code for test1will compile

例如下面的代码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()

Let's simply your test2()to

让我们简单test2()

constexpr char test3(unsigned i)
{
    return t<i>::value;
}

This will not compile for test3(0)because inside test3(), it cannot be proven that iis an unconditionalcompile-time expression. You would need constexprfunction parameters to be able to express that.

这不会编译 fortest3(0)因为 inside test3(),无法证明这i是一个无条件编译时表达式。您需要constexpr函数参数才能表达这一点。

Quote from the Standard

引用自标准

5.19 Constant expressions [expr.const]

5.19 常量表达式 [expr.const]

2 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:

— 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

— it is a non-static data member of an object whose lifetime began within the evaluation of e;

2 条件表达式 e 是核心常量表达式,除非按照抽象机 (1.9) 的规则对 e 求值会求值以下表达式之一:

— 引用变量或引用类型数据成员的 id 表达式,除非该引用具有前面的初始化,并且
— 使用常量表达式初始化或

——它是一个对象的非静态数据成员,其生命周期开始于 e 的计算;

This section has the following code example corresponding to your question:

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

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;
}

Because xin the above example is not a constant expression, it means that you can't instantiate templates with either xor kinside f1.

因为x在上面的例子中不是一个常量表达式,这意味着你不能用xkinside实例化模板f1

回答by Useless

There's a misconception of what constexprdoes here. It indicates that a function must be evaluatable at compile time for suitable arguments, but it does notremove the requirement still to compile in the general case.

对这里的作用存在误解constexpr。它表明一个函数必须在编译时对合适的参数进行评估,但它并没有消除在一般情况下仍然编译的要求。

Let's take the first version:

我们来看第一个版本:

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

Now, this is clearly a compile-time evaluation:

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

enum { CompileTimeConstant = test1("Test", 0) };

your example maybe, but it's an optimizer/QoI issue:

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

char MayBeCompileTimeConstant = test1("Test", 0);

and this example obviously isn't, but is still required to be evaluatable

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

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

Since test2can't possibly compile in for the last case, it can't compile at all. (Please note I'm not suggesting that code is good).

由于test2无法为最后一种情况编译,因此根本无法编译。(请注意,我并不是在暗示代码是好的)。

回答by 101010

The problem here is that calling arr[i]evokes the subscript operator operator[]. This operator doesn't return a constant expression.

这里的问题是调用会调用arr[i]下标操作符operator[]此运算符不返回常量表达式。

It's not a problem of constexpractually, is a problem of template argument deduction. A Non type template argument must be a constant expression which the return argument of subscript operator is not.

这不是constexpr实际上的问题,是模板参数推导的问题。Non 类型模板参数必须是一个常量表达式,而下标运算符的返回参数不是。

Therefore, the compiler rightfully complains that arr[i]is not a constant expression.

因此,编译器理所当然地抱怨这arr[i]不是一个常量表达式。

回答by user1742529

Because arr[i]is not compile-time constant expression. It can be different at run-time.

因为arr[i]不是编译时常量表达式。它可以在运行时不同。