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
}
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.
来源:https://stackoverflow.com/questions/24580714/why-is-this-not-a-constant-expression