Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'operator =' is ambiguous for std::string

Tags:

c++

c++11

I am trying to write a class with my own cast operators but I am having issues with multiple operator=s

I managed to reproduce the issue with the small code below

#include <string>

class X
{
public:
  operator const char*() const {
    return "a";
  }
  operator std::string() {
    return "c";
  }
};

void func( )
{
  X x;
  std::string s = "";
  s = x;
}

I understand that std::basic_string has multiple assignment operator and this is why the compiler gets confused.

If I remove either cast operators it works, but I was wondering if there was a way of keeping both operators.

My class will be returning different values depending on the cast.

I could also use static_cast<std::string>(x) to force the cast, but I was wondering if there was a a way of doing it without the static cast?

like image 312
Simon Goodman Avatar asked Oct 07 '16 21:10

Simon Goodman


2 Answers

As KerrekSB suggested, you can use

s = std::string(x);

Alternatively, you can perform a cast:

s = (std::string) x;
// or
s = static_cast<std::string>(x);

A third alternative (which I would hope not to see in the wild very often due to readability concerns) is to access the operator directly:

s = x.operator std::string();

If you're willing to make the tradeoff of a slightly different API (and fixing any potential breakages) you can do what Roberto suggested and force the explicit casting of just the const char * type operator:

class X
{
public:
  explicit operator const char*() const {
    return "a";
  }
  operator std::string() {
    return "c";
  }
};

This tells the compiler to only allow implicit conversions to std::string, and requires you do explicitly cast to const char * when you want to invoke that particular operator.


One last thing to note: if you are designing other classes or methods that would consume this particular class, another thing to try is to reverse the way they're used by providing an overload for class X rather than converting X to something else.

Always good to consider alternative ways for your API to work.

like image 50
Qix - MONICA WAS MISTREATED Avatar answered Oct 08 '22 21:10

Qix - MONICA WAS MISTREATED


If you use explicit keyword on char* cast you'll default casting to std::string.

class X
{
public:
    explicit operator const char*() const {
        return "a";
    }
    operator std::string() {
         return "c";
    }
};

after it your casts:

X x;
std::string s = "";
s = x;

will succeed (and the user of your class will need to specify char* cast if he wants to use the other cast)

Any way, as a user of your class I would rather prefer if both castings are explicit, so I know when a casting is being made

like image 44
Roberto Avatar answered Oct 08 '22 20:10

Roberto