Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this cast ambiguous?

Tags:

c++

c++11

I have a class that I have written which does type erasure. The public interface is:

template <typename T>
value(const T &t);

value(value &&v);

template <typename T>
operator T() const;

When I create a value instance from a std::string I have no problems, everything works as expected. When I try to get the std::string back out, using static_cast<std::string>(val), where val is an instance of value that is holding a std::string, I get the following error from VS2012:

error C2440: 'static_cast' : cannot convert from 'value' to std::string'

No constructor could take the source type, or constructor overload resolution was ambiguous

If I comment out the templated cast operator and add operator std::string() const then it compiles. I figure that something between the std::string constructors and the templated cast operator have the same goodness of match. Could anyone suggest what is happening and how to fix it?

like image 904
Graznarak Avatar asked Aug 30 '13 17:08

Graznarak


Video Answer


3 Answers

Igor explained the problem. Here's my suggested solution:

Your class is obviously only intended to store one type of object at a time, so make that explicit. Replace the conversion functions with a real function:

template <typename T>
T get() const;

Now call it like this:

std::string myString = myValue.get<std::string>( );

No ambiguity. No chance of the wrong function being called and messing everything up. And I'd argue that it is now more readable.

like image 69
Dave Avatar answered Oct 04 '22 21:10

Dave


std::string has several constructors capable of being called with one parameter - e.g. one taking const string&, and another taking const char*. What should T resolve to, then?

From the C++ standard:

5.2.9p4 Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t.

In your case, the declaration std::string t(val); is ill-formed.

like image 26
Igor Tandetnik Avatar answered Oct 04 '22 21:10

Igor Tandetnik


Following works with std::string (if you can return a reference).

static_cast<const std::string&>(val);
like image 37
Jarod42 Avatar answered Oct 04 '22 21:10

Jarod42