2

I am trying to make utility for converting strings as I have a bad mix of interfaces needing strings in various containers (char*, std::string, custom string type) and formats (utf-8, utf-16, utf-32). So I had the idea to create a wrapper with cast operators to the various types. Like this:

#include <iostream>
#include <string>

struct X {
    operator std::string() { return std::string("string x"); }
    operator const char *() { return "zstring x"; }
};

X make_x() { return X(); }

int main()
{
    std::string y = make_x(); // this works
    std::string y(make_x()); // but this does not
    y = make_x(); // this does not work either
    y = std::string(make_x()); // nor does this, so it's about useless
    std::cout << y << std::endl;
    return 0;
}

But the problem is that if the type converts to both char * and std::string, the std::string constructor and assignment will be ambiguous between those two types. And I don't want to go through just char *, because the string may be originally given by range rather than as nul terminated, requiring extra copy to get a nul terminated one as well as making embedded nuls not work.

So is there any way to disambiguate these?

Important note: I am stuck with some C++03 compilers, so neither cast operator can be marked explicit.

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
Jan Hudec
  • 73,652
  • 13
  • 125
  • 172

2 Answers2

1

Explicitly cast the result of make_x() so std::string, const char* or whatever before passing it as a function argument, e. g.:

std::string y(static_cast<const char*>(make_x()));

If you need to do this a lot and consider it to verbose, give the cast operators short names:

struct X {
    std::string str() { return std::string("string x"); }
    const char *cstr() { return "zstring x"; }
};

std::string y(make_x().str());

If this is unacceptable too, adapt the safe bool idiom to your purpose.

David Foerster
  • 1,461
  • 1
  • 14
  • 23
  • Static cast does not work either. It's mentioned in the question. Safe bool idiom relies on existence of type, that has _implicit_ conversion to bool, but there are no implicit conversions to char *. – Jan Hudec Jun 12 '13 at 08:54
  • Yeah, forget the part about the safe bool idiom (brain fart). I find it curious, that explicit casts don't work in this instance, since I excepted them to call the corresponding cast operator, if one exists. Depending on what you need exactly, member functions are probably the easiest clean solution. – David Foerster Jun 12 '13 at 09:06
  • The function-call cast means "construct a temporary", so I am not surprised it is as ambiguous as variable construction. I have also expected `static_cast` to use the cast operator only if it exists, but unfortunately it just does the same and tries all constructors. – Jan Hudec Jun 12 '13 at 09:55
1

I ended up creating one helper with cast operator to any character (char, wchar_t and either uint16_t or uint32_t depending on whether wchar_t is 32 or 16 bit) pointer type and another helper with cast operator to any basic_string (specialized to any of above, using custom traits for the non-standard types). That does not appear to be ambiguous anywhere.

Jan Hudec
  • 73,652
  • 13
  • 125
  • 172