Reputation: 51
I have code to overload the conversion operator for different types:
#include <string>
#include <iostream>
class MyClass {
int m_int;
double m_double;
std::string m_string;
public:
MyClass() : m_int{1}, m_double(1.2), m_string{"Test"} {};
// overload the conversion operator for std::string
operator std::string() {
return m_string;
}
// overload the conversion operator for all other types
template <typename T>
operator T() {
if (std::is_same<T, int>::value)
return m_int;
else
return m_double;
}
};
int main() {
MyClass o;
int i = o;
double d = o;
std::string s = o;
std::cout << i << " " << " " << d << " " << s << std::endl;
}
This works correctly. But when I try do do
std::string s;
s = o;
the compilation fails with
error: use of overloaded operator '=' is ambiguous (with operand types 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') and 'MyClass')
Apparently the compiler instantiates a conversion operator different than std::string(). If I remove the template section, the compiler is forced to use the std::string() conversion operator and it works again. So what am I missing?
Upvotes: 2
Views: 308
Reputation: 51
Got it kind of working (thanks to my colleague NB):
#include <string>
#include <iostream>
class MyClass {
int m_int;
double m_double;
std::string m_string;
public:
MyClass() : m_int{1}, m_double(1.2), m_string{"Test"} {};
// overload the conversion operator for std::string
operator std::string() {
return m_string;
}
// overload the conversion operator for all other types
template <typename T, typename std::enable_if<
std::is_same<T, int>::value ||
std::is_same<T, double>::value
,T>::type* = nullptr>
operator T() {
if (std::is_same<T, int>::value)
return m_int;
else
return m_double;
}
};
int main() {
MyClass o;
int i = o;
double d = o;
std::string s;
s = o;
std::cout << i << " " << " " << d << " " << s << std::endl;
}
So one has to enable the template for all valid types. But as soon as (char) is in the type list under std::enable_if<>, the error occurs again. Apparently the std::string= operator wants to map to char
(See item 4. above).
What I do not understand right now is why explicitly specifying the int() and double() conversion operators explicitly does NOT work:
operator int() {
return m_int;
}
operator double() {
return m_double;
}
although this should be equivalent to
template <typename T, typename std::enable_if<
std::is_same<T, int>::value ||
std::is_same<T, double>::value
,T>::type* = nullptr>
operator T() {
if (std::is_same<T, int>::value)
return m_int;
else
return m_double;
}
Also not clear why this does not work:
template <typename T, typename std::enable_if<
std::is_same<T, int>::value ||
std::is_same<T, double>::value ||
std::is_same<T, std::string>::value
,T>::type* = nullptr>
operator T() {
if (std::is_same<T, std::string>::value)
return m_string;
else if (std::is_same<T, int>::value)
return m_int;
else
return m_double;
}
Maybe someone can give me some insight.
Upvotes: 0
Reputation: 8427
In std::string
class, it is possible to use operator=()
to assign characters (and as a result integers) to the std::string
. It means that the following code is acceptable because the operator=(char)
does exist:
std::string s1;
s1 = '1'; // works fine
s1 = 24; // works fine
But you cannot copy construct an string using characters (and so integers).
std::string s2 = '1'; // compilation fails
std::string s3 = 24; // compilation fails
So, in your case, when you use copy-construction, there is no ambiguity, because std::string
cannot be copy constructed using double or int. But for operator=
it is ambiguous because you can assign integers into a string and the compiler does not know which conversion operator to use. In other words, the compiler can use both your string and int conversion operators for that.
Upvotes: 3