Why is this not a constant expression?

▼魔方 西西 提交于 2019-12-18 18:46:49

问题


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

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
}

回答1:


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.




回答2:


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).




回答3:


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.




回答4:


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



来源:https://stackoverflow.com/questions/24580714/why-is-this-not-a-constant-expression

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