I have the following code:
#include <iostream>
template<int I>
class A
{
public:
inline constexpr static int size() { return I; }
};
template<typename T>
inline constexpr auto size(const T& arg) noexcept -> decltype(arg.size())
{
return arg.size();
}
template<typename T>
inline constexpr void twoLevel(const T& arg) noexcept
{
static_assert(size(arg) > 0);
}
int main()
{
A<5> a;
static_assert(size(a)>0); //this works
twoLevel(a); // this does not
return 0;
}
Which fails to compile on msvc with the error expression did not evaluate to a constant
, but works with gcc. Is it gcc accepting something that's undefined behaviour? Or is it a compiler bug on msvc's part? Here's a demo: godbolt code
From [expr.const]/4 :
An expression
e
is a core constant expression unless the evaluation ofe
, following the rules of the abstract machine, 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 usable in constant expressions or
- its lifetime began within the evaluation of
e
;- [...]
In:
static_assert(size(arg) > 0);
We have an id-expression that refers to a variable of reference type, and the reference does not have preceding initialization, so we do not have a constant expression.
I think this:
static_assert(size(a) > 0);
works because of "preceding initialization" - we enter constant evaluation by directly binding the reference arg
to the variable a
, whereas in the other case we're binding a reference to another reference.
Both should work if you take by value though.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.