implicit and explicit conversion from my class to string

321 Views Asked by At

My class is like:

class X {

public:
        :
        :
        :
  operator const char*() const { return "foo"; };
  operator std::string() const { return std::string( "foo" ); };
        :
        :
        :
};

My hope was to be able to initialize a std::string implicitly, like this, but huge wall of errors:

string s1( x );

Even explicitly doesn't work:

string s1( (string) x );

However casting x to (const char*) works fine:

string s1( (const char*) x );

In addition to whatever solution you guys have, any other recommendations for making a type that should be as freely-convertible to and from C-style strings and std:string? (I already have constructors for X taking const char* and std::string as well as an x, and can take assignments from those types.

1

There are 1 best solutions below

1
Daniel Langr On

I am not sure my explanation will be 100% precise, but if not, hopefully, someone will clarify it. Instead of std::string and char*, I will use a custom Y class and int for the sake of simplicity:

struct Y 
{
   Y(int) { }
};

struct X
{
   operator int() const { return 1; }
   operator Y() const { return Y(0); }
};

int main()
{
   X x;
   Y y(x);
}

With this code, in C++11/14, the compiler has two options how to proceed:

  1. It converts x to Y(0) by X::operator Y() and then passes this Y(0) to the move constructor of Y.

  2. It converts x to int(1) by X::operator int() and then passes this int(1) to the converting constructor Y::Y(int).

Both options are equivalent and, therefore, generate ambiguity, which results in a compilation error.


In C++17, the situation is different due to guaranteed copy elision. Here, the call of move constructor in (1.) is elided, and, consequently, the first conversion sequence is selected, since it requires only 1 conversion instead of 2.


Anyway, this version:

Y y(static_cast<Y>(x));

also generates ambiguity in C++11/14, which, I must admit, I do not understand.