For me, it looks like an error in MSVC, where it tries to be smart with a pointer array and makes a mistake.
Expand the second example:
The compiler must initialize const char*&& from an lvalue of type const char[13] . To do this, 8.5.3 says that it creates a temporary type const char* and initializes it with const char[13] , and then binds the link to a temporary one.
Initializing a const char* from const char[13] involves a simple conversion between arrays and pointers, which gives the value const char* , which is then copied to a temporary one.
Thus, the conversion is well defined, despite what MSVC says.
In the first example, this is not test () causing the problem, but a call to std::forward . std::forward<const char*> has two overloads, and MSVC does not complain, and is not viable. Two forms:
const char*&& std::forward(const char*&&); const char*&& std::forward(const char*&);
One takes the lvalue link, one takes the rvalue link. When considering whether overloading is viable, the compiler must find the sequence of the conversion from const char[13] to a reference to const char* .
Since the lvalue reference is not const (it is a reference to a pointer to const char, the pointer itself is not const), the compiler cannot apply the conversion sequence described above. In fact, no conversion sequence is valid, since conversion from an array to a pointer requires a temporary one, but you cannot bind non-constant lvalue references to temporary ones. Thus, MSVC correctly rejects the lvalue form.
The rvalue form, however, as I set above, should be accepted, but the MSVC is incorrectly rejected.