I am learning C++17 new feature decltype(auto)
for non-type template parameter. I wrote a simple code snippet as following:
#include <type_traits>
template<decltype(auto) arg>
struct Foo {};
int
main()
{
constexpr int x = 42;
static_assert(std::is_same_v<Foo<42>, Foo<x>>);
}
As I understand, Foo<42>
should be the same type as Foo<x>
.
However, The static_assert
statement compiles with clang++, MSVC 19.27 but fails with GCC 10.2, MSVC 19.25.
My question is: Why do compilers behave differently? What does the Standard say about this?
Link to Compiler Explorer:
clang++ https://godbolt.org/z/66M695
gcc https://godbolt.org/z/3v5Mhd
MSVC 19.25 https://godbolt.org/z/qP6v89
MSVC 19.27 https://godbolt.org/z/14aK5Y
It's all in the rules describing how
decltype
works.When using
decltype(auto)
,e
is the expression that is used as an initializer for our object (arg
). In the OP, this expression isx
. It's an unparenthesized id-expression, sodecltype(x)
would be the type of the entity named byx
. That type isint const
, because aconstexpr
specifier impliesconst
.So here's a cute modification to your code sample that makes GCC accept it.
Why is that? It's because
+x
is no longer an id-expression. It's a plain old prvalue expression of typeint
, having the same value asx
. So that's whatdecltype(auto)
deduces, anint
.All in all, the compilers that rejected your code are acting correctly. And I guess it goes to show you that using
decltype(auto)
for a non-type template parameter should come with a short disclaimer.