Using this program:
#include <sstream>
#include <iostream>
static std::ostringstream oss;
struct fmt
{
template <typename T>
fmt& operator<< (const T&& val)
{
oss << val;
return *this;
}
};
int main()
{
fmt() << "123";
std::cout << oss.str();
}
Visual Studio 2919 gives me this:
$ cl /EHsc rref.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30151 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
rref.cpp
rref.cpp(18): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const char [4]' (or there is no acceptable conversion)
rref.cpp(9): note: could be 'fmt &fmt::operator <<<char[4]>(const T (&&))'
with
[
T=char [4]
]
rref.cpp(18): note: while trying to match the argument list '(fmt, const char [4])'
If I use only T&& val (without "const") all goes well.
I can't understand the cause of the error.
What's the cause of the error, and how to fix it ?
A string literal such as
"123"is an lvalue expression, but you declared theoperator<<overload to accept only rvalues (because it takes aconstrvalue reference). You can't bind a rvalue reference (whether or not it isconst) to a lvalue.It should be
const T& valinstead ofconst T&& val. Aconstlvalue reference can bind to both lvalues and rvalues.Maybe you wanted
valto be a forwarding reference instead which can be deduced to either a lvalue reference or a rvalue reference, but that only makes sense if you actually forward it in the body withstd::forward.const T&&is however not a forwarding reference and the special deduction rules do not apply to it. It will always be deduced to aconstrvalue reference. Only a function parameter with a type which consists of a template parameter directly applied with&&constitutes a forwarding reference with the special deduction rules.In general
constin combination with&&is usually useless, except in certain situations to make overload sets not accept rvalue arguments (by= deleteing the overload).