boost-ext / te

C++17 Run-time Polymorphism (Type Erasure) library
463 stars 39 forks source link

No support for move-only types #3

Closed ArekPiekarz closed 6 years ago

ArekPiekarz commented 6 years ago

te doesn't seem to support move-only types, even though in the presence of move constructor and rvalue it will move the object and not use the copy constructor.

For example, given the following code that prints all calls to member functions of a tested class Circle:

#include "external/te/include/te.hpp"
#include <iostream>

using std::cout;

struct Drawable
{
    void draw(std::ostream &out) const
    {
        te::call([](auto const &self, auto &out) { self.draw(out); }, *this, out);
    }
};

struct Circle
{
    Circle() { cout << "Circle()\n"; }
    Circle(const Circle&) { cout << "Circle(const Circle&) ctor\n"; }
    Circle& operator=(const Circle&) { cout << "operator=(const Circle&)\n"; }
    Circle(Circle&&) { cout << "Circle(Circle&&)\n"; }
    Circle& operator=(Circle&&) { cout << "operator=(Circle&&)\n"; }
    ~Circle() { cout << "~Circle()\n"; }

    void draw(std::ostream &out) const { out << "Circle::draw\n"; }
};

void draw(const te::poly<Drawable>& drawable) { drawable.draw(cout); }

int main()
{
    Circle circle{};
    draw(std::move(circle));
}

we will get this output:

Circle()
Circle(Circle&&)
Circle::draw
~Circle()
~Circle()

But when we try to mark the copy constructor and copy assignment operator as deleted as below:

struct Circle
{
    Circle() { cout << "Circle()\n"; }
    Circle(const Circle&) = delete;
    Circle& operator=(const Circle&) = delete;
    Circle(Circle&&) { cout << "Circle(Circle&&)\n"; }
    Circle& operator=(Circle&&) { cout << "operator=(Circle&&)\n"; }
    ~Circle() { cout << "~Circle()\n"; }

    void draw(std::ostream &out) const { out << "Circle::draw\n"; }
};

we will get a compilation error:

main.cpp:33:19: error: invalid initialization of reference of type ‘const te::v1::poly<Drawable>&’ from expression of type ‘std::remove_reference<Circle&>::type {aka Circle}’
     draw(std::move(circle));
          ~~~~~~~~~^~~~~~~~
main.cpp:28:6: note: in passing argument 1 of ‘void draw(const te::v1::poly<Drawable>&)’
 void draw(const te::poly<Drawable>& drawable) { drawable.draw(cout); }
      ^~~~

Are there any plans to support noncopyable types?

Environment OS: Ubuntu 17.10 x64 Compiler: GCC 7.2 x64