I am a bit confused by this. Lets assume I have a helper class Data
class Data
{
public:
Data(const QVariant &value) : m_Variant(value) { }
operator QString() const { return m_Variant.toString(); }
private:
QVariant m_Variant;
};
then when I do this:
Data d("text");
QString str = d; //str becomes "text"
it works but when I continue to do:
Data d2("text2");
str = d2; //does not compile
it fails complaining:
ambiguous overload for 'operator=' (operand types are 'QString' and 'Data')
candidates are:
...
QString &operator=(const QString &);
QString &operator=(QString &&);
QString &operator=(const char*); <near match>
no known conversion from Data to const char*
QString &operator=(char);
But even providing
operator const char*() const;
does not help. The message about conversion just disappears and the error remains the same. Is there a way to solve this other than adding
QString &operator=(const Data &data);
to QString
or calling explicitly
str = QString(d2);
?
I am confused because the compiler clearly deduced correctly that the left operand is a QString
and it is apparently trying to call conversion from Data
to what would one of the QString
's operator=
s accept but even if such conversion is defined it still does not work.
EDIT:
The problem seems to come from multiple definitions of different operator T()
members. In this case operator int()
.
I haven't got access to an online compiler with the Qt libraries, but here's what I pieced together from the public documentation of QString
and QVariant
:
#include <iostream>
struct QString
{
QString() = default;
QString(QString const&) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
QString &operator=(const QString &) { std::cout << __PRETTY_FUNCTION__ << '\n'; return *this; }
QString(char const*) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
QString &operator=(const char*) { std::cout << __PRETTY_FUNCTION__ << '\n'; return *this; }
QString(char) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
QString &operator=(char) { std::cout << __PRETTY_FUNCTION__ << '\n'; return *this; }
};
struct QVariant
{
QVariant(QString const&) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
QVariant(char const*) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};
struct Data
{
Data(QVariant const&) { std::cout << __PRETTY_FUNCTION__ << '\n'; }
operator QString() const { std::cout << __PRETTY_FUNCTION__ << '\n'; return QString(); }
operator int() const { std::cout << __PRETTY_FUNCTION__ << '\n'; return QString(); }
};
int main()
{
Data d("text");
QString str = d;
Data d2("text2");
str = d2;
}
The direct-initializations of d("text")
and d2("text2")
, convert char const* -> QVariant
through the constructors
QVariant::QVariant(const char*)
Data::Data(const QVariant&)
The copy-initialization QString str = d
elides a call to the QString
copy constructor on a temporary QString
object produced by
Data::operator QString() const
Now for the bug: the assignment of str = d2
tries to match the various assignment operators QString::operator=
overloads to your Data
argument. Once Data
has multiple conversion operators (to QString
and to int
e.g.), you will get an overload resolution ambiguity because QString
has both the regular assignment operator=(QString)
as well as the operator=(char)
(which can take int
).
TL;DR there is only one route for construction: char const* -> QVariant -> Data
. But there are two routes Data -> QString
and Data -> int -> char
that lead to a valid argument for the assignment operator.
Fix: use explicit
conversion operators in your own code (or remove one or more of them).
来源:https://stackoverflow.com/questions/32651971/operator-t-not-used-in-assignment