c++rvalue-reference

What's causing the error in this example using a const rvalue reference parameter?


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 ?


Solution

  • 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 = deleteing the overload).