5

Consider the following example:

#include <string>
#include <sstream>

struct Location {
    unsigned line;

    template<typename CharT, typename Traits>
    operator std::basic_string<CharT, Traits>() const {
        std::basic_ostringstream<CharT, Traits> ss;
        ss << line;
        return ss.str();
    }
};

int main() 
{
    using namespace std::string_literals;

    Location loc{42};

    std::string s1 = "Line: "s.append(loc) + "\n"s; // fine
    //std::string s2 = "Line: "s + loc + "\n"s; // error
}

The commented line causes a compilation error: no match for 'operator+'. Why? My initial thought was that it would first use operator std::string to convert and then perform the call to operator+, the same way it does for .append.

It is only one level of implicit conversion, so it should be performed and it should be taken into account, no?

Live Demo

5
  • Sorry for asking, but I don't see to get the working code. What is s? Commented Oct 20, 2017 at 6:23
  • 3
    @gsamaras en.cppreference.com/w/cpp/string/basic_string/operator%22%22s Commented Oct 20, 2017 at 6:24
  • Right @Holt, thanks! Commented Oct 20, 2017 at 6:29
  • 2
    The problem here is that when you do .append, the template arguments are already instantiated during construction of "Line"s, so there is no template argument deduction taking place (.append wants std::string), but the + operator is templated, so you need to deduce CharT, Traits and Allocator, and you cannot because the compiler cannot match basic_string<...> against Location - You don't even reach the conversion phase, it's the overload phase that fails. Commented Oct 20, 2017 at 6:33
  • @Holt Thank you. A technical explanation is what I was searching for. I'd accept if you posted as a full answer. Commented Oct 20, 2017 at 6:34

2 Answers 2

2

Your operator is templated, thus the template arguments need to be deduced. You cannot do that, since the compiler tries to match basic_string<_CharT, _Traits, _Alloc> to your Location, and it fails.

So the problem is the overloading, not the conversion, since the code actually never reaches that point.

Change this:

std::string s2 = "Line: "s + loc + "\n"s;

to this:

std::string s2 = "Line: "s + std::string(loc) + "\n"s;

and you should be fine, since if you look closely at the compiler error, it mentions:

template argument deduction/substitution failed:
prog.cc:22:32: note:   'Location' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>'
   std::string s2 = "Line: "s + loc + "\n"s; // error
                                ^~~

and other similar messages.

Sign up to request clarification or add additional context in comments.

Comments

0

Explicit cast to std::string works for me: https://godbolt.org/g/WZG78z

    std::string s2 = "Line: "s + std::string(loc) + "\n"; // was error

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.