Consider the following code:
struct wrapper {
int& ref;
constexpr wrapper(int& ref) : ref(ref) {}
};
template <auto&& X>
void fun1() {}
template <wrapper X>
void fun2() {
fun1<X>();
}
int main() {
static int val = 22;
fun2<val>();
}
fun2<X>() takes in a class as non-type template parameter while fun1<X>() takes in a forwarding reference to any object passed to it.
The above fails to compile in GCC with the error shown below but compiles just fine in Clang.
<source>:11:12: error: the address of 'wrapper{val}' is not a valid template argument
11 | fun1<X>();
| ~~~~~~~^~
Which compiler is correct here? Is this supposed to be a bug in either of the two compilers?
I tried to change template <wrapper X> to template <const wrapper& X>, but to no avail, as it fails on both GCC and Clang.
Your code is valid. This is possibly a GCC bug. I've submitted a bug report, see GCC Bug 113242 - g++ rejects-valid template argument of class type containing an lvalue reference.
- [temp.arg.nontype] p3
The reference
auto&& Xrefers to an objectwrapper Xthat is none of those, so it should be a valid template argument.Note that what happens in
mainis effectively:Also note that the unqualified-id
Xinfun1<X>()is an lvalue of typeconst wrapper([expr.prim.id.unqual] p2). Therefore, the reference binding is direct and no temporaries are involved.Second Example
Both compilers are correct in rejecting
... because
fun2<val>()makesXbind to a temporarywrapperobject, created within the function call tofun2.