Inheriting copy and move constructors of base class using "using" keyword
Asked Answered
E

1

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.

Estrous answered 1/3, 2018 at 7:55 Comment(11)
Pretty_Function is not standard.Antepenult
@JiveDadson, but it is still pretty.Estrous
Not on my compiler. It is missing.Antepenult
This is not possible. A copy constructor is not inherited, neither as a copy constructor nor as a converting constructor.Fabre
@n.m., but why? Why can I inherit assignment operator but cannot inherit copy/converting constructor? It's a little bit strange for me.Estrous
if you don't want to reimplement copy and move ctors, couldn't you just delegate to them in the derived class?Chez
@solstice333, see JiveDadson answer: https://mcmap.net/q/189732/-inheriting-copy-and-move-constructors-of-base-class-using-quot-using-quot-keywordEstrous
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".Fabre
@Estrous ah, ok, yup that's pretty much delegation. ThanksChez
@n.m., OK, but why does using A::operator=; still work then?Estrous
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. Note it only applies to constructors not to assignment operators.Fabre
A
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)) {}
};
Antepenult answered 1/3, 2018 at 8:24 Comment(4)
I don't need to add default constructor explicit. It works without it (coliru.stacked-crooked.com/a/bf8d566e8575fbe6). Adding constructor from A to B is what I'm trying to avoid.Estrous
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.Antepenult
I don't know. I've just shown you an example that it compiles fine without B() = default;. But maybe it is gcc extension.Estrous
In any case, you have the answer. Good luck.Antepenult

© 2022 - 2024 — McMap. All rights reserved.