Search code examples
c++type-conversionimplicit-conversionrefreference-wrapper

std::ref implicit conversion to reference confusion


I know that a std::ref(object) creates a std::reference_wrapper(object), and that std::reference_wrapper has a non-explicit type conversion operator member function

operator T&() const

and I know that this influences how I use it when template parameter deduction comes into play: so in Print below, the type T of the argument is deduced as std::reference_wrapper if I call it with,say, std::ref("hello")

template <class T>
void Print(T t)
{
    std::cout << t << std::end;
}

Why doesn't this line compile?

std::string s = "hello";
std::cout << std::reference_wrapper<std::string>(s) << std::endl;

the instantiated specialization should have a

operator std::string&() const

type conversion function, so why can't I use a reference wrapper like this?


Solution

  • The operator<< overload that you are trying to use has the following form (from cppreference.com):

    template <class CharT, class Traits, class Allocator>
    
    std::basic_ostream<CharT, Traits>&
        operator<<(std::basic_ostream<CharT, Traits>& os,
                   const std::basic_string<CharT, Traits, Allocator>& str);
    

    The second function parameter contains template parameters and is not a non-deduced context. Therefore it must deduce the template arguments. Implicit conversions are not considered for template argument deduction and since std::reference_wrapper is not a std::basic_string, deduction will fail. It doesn't matter whether std::reference_wrapper can be converted to std::string (or a reference to one).

    And just to clarify, std::string is an alias for the specialization std::basic_string<char, std::char_traits<char>, std::allocator<char>> of std::basic_string. std::basic_string can be specialized for any character type, for example wchar_t (which is aliased as std::wstring). Other specializations are simply not often used.