4

I just made a wrapper for move and copy operations to inject into code to see which is called in case of default implementations. I'm getting close to understanding when what is called but would like to double check at times.

I'm not sure if method 1 of using T::T; is better for the constructors than method 2 of forwarding the arguments like unique_ptr? I found it in this thread Forwarding all constructors in C++0x

In move constructor and assignment I use std::move to pass onto the super class. Should this be std::forward and if so, how? I get errors trying to use it.

#ifndef MOVECOPY_OBSERVER_H
#define MOVECOPY_OBSERVER_H

#include <iostream>

template<class T>
class MoveCopyObserver : public T {
public:
    //1: Use "using" for constructors 
    //From https://stackoverflow.com/questions/3119929/forwarding-all-constructors-in-c0x
    using T::T;

    //2: Forward all args, unique_ptr style.
    /*
    template<typename... Args>
    MoveCopyObserver(Args&&... args) 
        : T(std::forward<Args>(args)...) 
    {
    };*/

    // *************************************************************************
    virtual ~MoveCopyObserver() = default;


    // *************************************************************************
    MoveCopyObserver(const MoveCopyObserver& other)
        : T(other)
    {
        std::cout << "Copy constructor " << typeid(T).name() << std::endl;
    }


    // *************************************************************************
    MoveCopyObserver(MoveCopyObserver && other)
        : T(std::move(other)) //3: std::forward instead?
    {
        std::cout << "Move constructor " << typeid(T).name() << std::endl;
    }


    // *************************************************************************
    MoveCopyObserver& operator=(const MoveCopyObserver& other)
    {
        T::operator=(other);
        std::cout << "Copy assignment " << typeid(T).name() << std::endl;
        return *this;
    }


    // *************************************************************************
    MoveCopyObserver& operator=(MoveCopyObserver&& other)
    {
        T::operator=(std::move(other)); //3: std::forward instead?
        std::cout << "Move assignment " << typeid(T).name() << std::endl;
        return *this;
    }
};


#endif //MOVECOPY_OBSERVER_H

The usage would be on the stack or through smart pointers, like so:

class A {
public:
    A(std::string ss)
    {
        s = ss;
    }

    void f()
    {
        std::cout << "\"" << s << "\"" << std::endl;
    }

private:
    std::string s;
};

A a("Test instance");
a.foo();

MoveCopyObserver<A> b("Another instance");
b.foo();
Community
  • 1
  • 1
Sheph
  • 625
  • 1
  • 6
  • 19
  • For the question about using `using T::T;` vs a template catch all constructor, the former is the proper way. After testing I found that the template catch all _also_ catches the Copy Constructor and as such the wrapping copy constructor was never called. Using `using T::T;` makes this work. – Sheph May 05 '16 at 14:27
  • The way you asked this sounds like a code review question, unless you're running into a particular problem with your code that you're trying to solve. If you're mostly looking for a code review, I think this site might better suit your needs - http://codereview.stackexchange.com/ – Merlyn Morgan-Graham Jun 08 '16 at 10:49

1 Answers1

0

The other question addresses the point of inheriting constructors, which are indeed superior to a forwarding wrapper in several ways. Note that neither approach gives you the copy/move constructors (for different reasons), which is good here since you want to log those.

std::forward is for, well, forwarding references; you don’t have or need any of those (even T&& is a normal rvalue reference in a class template), so std::move is correct here.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76