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 the operator<<
overload to accept only rvalues (because it takes a const
rvalue reference). You can't bind a rvalue reference (whether or not it is const
) to a lvalue.
It should be const T& val
instead of const T&& val
. A const
lvalue reference can bind to both lvalues and rvalues.
Maybe you wanted val
to 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 with std::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 a const
rvalue 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 const
in combination with &&
is usually useless, except in certain situations to make overload sets not accept rvalue arguments (by = delete
ing the overload).