#include <cstddef>
template<typename... Types>
constexpr std::size_t getArgCount(Types&&...) noexcept
{
return sizeof...(Types);
}
struct A
{
int n;
void f()
{
static_assert(getArgCount(n) > 0); // not ok, why?
}
};
int main()
{
int n;
static_assert(getArgCount(n) > 0); // ok
}
Why can't I get the argument count of a template function at compile-time?
error message:
1>test.cpp
1>test.cpp(17,45): error C2131: expression did not evaluate to a constant
1>test.cpp(17,42): message : failure was caused by a read of a variable outside its lifetime
1>test.cpp(17,42): message : see usage of 'this'
Anything that accesses this
outside constexpr
context is not a constant expression, as defined in [expr.const]/2.1:
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
this
, except in aconstexpr
function or aconstexpr
constructor that is being evaluated as part of e;
(We need this
to access n
in order to pass it to getArgCount
by reference)
So that's why the first case doesn't compile.
The second case compiles because it doesn't involve an lvalue-to-rvalue conversion of a non-constant (sizeof(n)
does not actually "read" n
).
To demonstrate this, the following will also compile:
struct A
{
int n;
void f()
{
int m = n;
static_assert(getArgCount(m) > 0); // ok, m doesn't need `this`
}
};
Note: Having a reference inside a constexpr
context (the Types&&
part) by itself doesn't break "constexpr-ness" if the lifetime of the reference began within that context: [expr.const]/2.11.2.
Another example:
struct A
{
int n;
void f()
{
static_assert(sizeof(n) > 0); // ok, don't need this for sizeof(A::n)
}
};
The following won't compile:
int n = 1;
static_assert(getArgCount(n+1) > 0); // not ok, (n+1) "reads" n
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With