vendredi 26 mai 2017

How to apply move constructor while inheriting from template class

When I run the code below it produces the following output, (The difference is shown in bold)

Template Dummy: initializing constructor
Template Dummy: initializing constructor
Template Dummy: empty constructor
Template Dummy: empty constructor
Template Dummy: + operator
Template Dummy: move assignment
2

Template Dummy: initializing constructor
Template Dummy: initializing constructor
Template Dummy: empty constructor
Template Dummy: empty constructor
Template Dummy: + operator
Template Dummy: copy constructor
Template Dummy: copy assignment
2

The reason, I think, is clear - naming an argument turns the argument into an lvalue, thus the template receives an lvalue and invokes a copy constructor.

The question is how to force move semantics in this case?

  #include <iostream>

  using namespace std;

  template <typename T> class Dummy {

  public:

    T val;

    Dummy& operator=(const Dummy& d){
      val = d.val;
      cout << "Template Dummy: copy assignment\n" ;
      return *this;
    }

    Dummy operator+(const Dummy &d) {
      Dummy res;
      res.val = val + d.val;
      cout << "Template Dummy: +  operator\n" ;
      return res;
    }

    // constructors
    Dummy() {
      val = 0;
      cout << "Template Dummy: empty constructor\n" ;
    }

    Dummy(const T v) {
      val = v;
      cout << "Template Dummy: initializing constructor\n" ;
    }

    Dummy(const Dummy &d) {
      val = d.val;
      cout << "Template Dummy: copy constructor\n" ;
    }

    // move semantics
    Dummy(const Dummy&& d) {
      val = d.val;
      cout << "Template Dummy: move constructor\n" ;
    }

    Dummy& operator=(const Dummy&& d){
      val = d.val;
      cout << "Template Dummy: move assignment\n" ;
      return *this;
    }
  };

  class FloatDummy : public Dummy<float> {
  public:

      FloatDummy& operator=(const FloatDummy& d){
        Dummy<float>::operator=(d);
        return *this;
      }

      FloatDummy operator+(const FloatDummy &d) {
        return (FloatDummy) Dummy<float>::operator+(d);
      }

      // constructors
      FloatDummy() : Dummy<float>() {};
      FloatDummy(float v) : Dummy<float>(v) {}
      FloatDummy(const FloatDummy &d) : Dummy<float>(d) {}
      FloatDummy(const Dummy<float> &d) : Dummy<float>(d) {}

      // move semantics
      FloatDummy(const FloatDummy&& d) : Dummy<float>(d) {}

      FloatDummy& operator=(const FloatDummy&& d){

      // here d is already an lvalue because it was named
      // thus the template invokes a copy assignment    
      Dummy<float>::operator=(d);
      return *this;
    }
  };

  int main() {
    Dummy<float> a(1), b(1);
    Dummy<float> c;
    c = a + b;
    cout << c.val << '\n';;

    FloatDummy d(1), e(1);
    FloatDummy f;
    f = d + e;
    cout << f.val << '\n';
  }

Aucun commentaire:

Enregistrer un commentaire