1

I have a custom two dimensional point type, which has a template cast operator:

struct MyPoint
{
    double x, y;

    template < typename T >
    operator T() const
    {
        return T{ x, y };
    }
};

All works fine for std types:

auto p1 = MyPoint{ 1, 2 };
auto p2 = static_cast< std::array< double, 2 > >( p1 );
auto p3 = static_cast< std::pair< double, double > >( p1 );

But if I try the same thing with QPointF, I get this error (using g++ v4.8):

../CppTest/main.cpp:23:42: error: call of overloaded 'QPointF(MyPoint&)' is ambiguous
     auto p3 = static_cast< QPointF >( p1 );
                                          ^
../CppTest/main.cpp:23:42: note: candidates are:
In file included from /usr/include/qt5/QtCore/QPointF:1:0,
                 from ../CppTest/main.cpp:2:
/usr/include/qt5/QtCore/qpoint.h:270:18: note: constexpr QPointF::QPointF(const QPoint&)
 Q_DECL_CONSTEXPR inline QPointF::QPointF(const QPoint &p) : xp(p.x()), yp(p.y()) { }
                  ^
/usr/include/qt5/QtCore/qpoint.h:205:46: note: constexpr QPointF::QPointF(const QPointF&)
 class Q_CORE_EXPORT QPointF
                                              ^
/usr/include/qt5/QtCore/qpoint.h:205:46: note: constexpr QPointF::QPointF(QPointF&&)

It's like the compiler isn't even attempting to use the cast operator. If I change to an implicit conversion, such as:

QPointF p3 = p1;

It works fine. It also works if I use QPoint - it just seems to be QPointF that is causing problems, and I have no idea why.

cmannett85
  • 21,725
  • 8
  • 76
  • 119

1 Answers1

3

As far as I can tell the issue is that QPointF provides a constructor which takes a QPoint. When you do a static_cast the compiler tries to call QPointF(MyPoint&) and it sees two ways to create a QPointF from MyPoint:

  • Use the constructor taking a QPoint, by converting MyPoint to a QPoint first
  • Use any of the existing constructors that take a QPointF by converting MyPoint to a QPointF first.

Since there is more than one choice it is ambigous.

The copy initialization works because p1 is first converted to a QPointF and then the copy constructor is called.

The differences between QPointF p(...) and QPointF p = ... are discussed here.

To illustrate the point following is a small example which exhibits the same issue:

#include <iostream>

struct MyType
{
    template < typename T >
    operator T() const
    {
        return T{};
    }
};

struct A
{
    A() {}
    A(const A &) {}
};

struct B
{
    B() {}
    B(const A &) {}
    B(const B &) {}
};

int main()
{
    auto my = MyType{};
    auto a1 = static_cast<A>(my);
    //auto b1 = static_cast<B>(my); // fails
    B b2 = my;
}
Community
  • 1
  • 1
mfuchs
  • 2,190
  • 12
  • 20