Why is this not a constant expression?

落爺英雄遲暮 提交于 2019-11-30 17:09:37

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

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

E.g. the following code for test1 will compile

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

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

This will not compile for test3(0) because inside test3(), it cannot be proven that i is an unconditional compile-time expression. You would need constexpr function parameters to be able to express that.

Quote from the Standard

5.19 Constant expressions [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;

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 x in the above example is not a constant expression, it means that you can't instantiate templates with either x or k inside f1.

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

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 may be, but it's an optimizer/QoI issue:

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 test2 can't possibly compile in for the last case, it can't compile at all. (Please note I'm not suggesting that code is good).

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

It's not a problem of constexpr actually, 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.

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

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!