3

I want to inherit copy constructor of the base class using using keyword:

#include <iostream>

struct A
{
    A() = default;

    A(const A  &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
    A(      A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }

    A& operator=(const A  &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
    A& operator=(      A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
};

struct B : A
{
    using A::A;
    using A::operator=;

    B& operator=(const B  &) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
    B& operator=(      B &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; return *this; }
};

int main()
{
    A a;
    B b;
    b = a; // OK
    B b1(          a ); // compile error
    B b2(std::move(a)); // compile error
    return 0;
}

Inheriting assignment operator using using keyword works OK, but inheriting copy and move constructors causes a compilation error: an inherited constructor is not a candidate for initialization from an expression of the same or derived type.

http://coliru.stacked-crooked.com/a/fe84b429c391c894:

main.cpp:16:14: note:   an inherited constructor is not a candidate for initialization from an expression of the same or derived type
main.cpp:8:5: note: candidate: A::A(A&&)
     A(      A &&) { std::cerr << __PRETTY_FUNCTION__ << std::endl; }
     ^
main.cpp:16:14: note:   inherited here
     using A::A;

Why can I inherit assignment operator but cannot inherit copy constructor? What is a difference? I could understand if I couldn't inherit assignment operators too. But inheriting assignment operators in contrary is considered OK. That is a little strange for me.

The story

What I want is similar to what is asked in this question: I want to just add new methods to existing class without modifying it (it's a class from another library).

http://coliru.stacked-crooked.com/a/149a6194717cd465:

#include <iostream>

struct A // not my class
{
};

struct B : A
{
    using A::A;
    using A::operator=;

    void foo() { std::cerr << "fuu" << std::endl; }
};

A NotMyFunc()
{
    return {};
}

int main()
{
    B b(NotMyFunc());
    b.foo();
    return 0;
}

But I don't want to reimplement copy and move constructors.

anton_rh
  • 8,226
  • 7
  • 45
  • 73
  • __Pretty_Function__ is not standard. – Jive Dadson Mar 01 '18 at 08:28
  • 3
    @JiveDadson, but it is still pretty. – anton_rh Mar 01 '18 at 08:35
  • Not on my compiler. It is missing. – Jive Dadson Mar 01 '18 at 08:37
  • This is not possible. A copy constructor is not inherited, neither as a copy constructor nor as a converting constructor. – n. m. could be an AI Mar 01 '18 at 09:00
  • @n.m., but why? Why can I inherit assignment operator but cannot inherit copy/converting constructor? It's a little bit strange for me. – anton_rh Mar 01 '18 at 09:04
  • if you don't want to reimplement copy and move ctors, couldn't you just delegate to them in the derived class? – solstice333 Mar 01 '18 at 09:15
  • @solstice333, see JiveDadson answer: https://stackoverflow.com/a/49045417/5447906 – anton_rh Mar 01 '18 at 09:18
  • 1
    Because the standard says so. "If a constructor or assignment operator brought from a base class into a derived class has the signature of a copy/move constructor or assignment operator for the derived class (15.8), the using-declaration does not by itself suppress the implicit declaration of the derived class member; the member from the base class is hidden or overridden by the implicitly-declared copy/move constructor or assignment operator of the derived class". – n. m. could be an AI Mar 01 '18 at 09:19
  • @anton_rh ah, ok, yup that's pretty much delegation. Thanks – solstice333 Mar 01 '18 at 09:20
  • @n.m., OK, but why does `using A::operator=;` still work then? – anton_rh Mar 01 '18 at 10:13
  • 1
    Sorry this is a wrong justification! It doesn't work because "has the signature of a copy/move constructor or assignment operator for the **derived** class". It would work for `A::A(const B&)` but not for this case. The correct justification is [here](https://stackoverflow.com/a/28450893/775806). Note it only applies to constructors not to assignment operators. – n. m. could be an AI Mar 01 '18 at 11:46

1 Answers1

2

You need a constructor for B that has A as parameter. Then you need to make the default constructor explicit.

struct B : A
{
    using A::A;
    using A::operator=;

    B() = default;
    B(const A& a) : A(a) {}
    B(A &&a): A(std::move(a)) {}
};
Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
  • 1
    I don't need to add default constructor explicit. It works without it (http://coliru.stacked-crooked.com/a/bf8d566e8575fbe6). Adding constructor from `A` to `B` is what I'm trying to avoid. – anton_rh Mar 01 '18 at 08:33
  • You do need to make the default constructor explicit after you add the one-liner `B(const A& a) : A(a) {}`, which is required. Take it or leave it. – Jive Dadson Mar 01 '18 at 08:36
  • I don't know. I've just shown you an example that it compiles fine without `B() = default;`. But maybe it is _gcc_ extension. – anton_rh Mar 01 '18 at 08:38
  • In any case, you have the answer. Good luck. – Jive Dadson Mar 01 '18 at 08:40