Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting copy constructor breaks inherited constructors

I am trying to use the constructor inheritance feature of C++11. The following snippet (copied from somewhere, I don't remember whence) works completely fine:

#include <iostream>

struct Base {
  Base() : Base(0) {}
  Base(int a) : Base(a, 0) {}
  Base(int a, double b) { std::cout << "Base(" << a << "," << b << ")" << std::endl; }
};

struct Derived : Base {
  using Base::Base;
  Derived(const Derived& that) = delete;  // This line is the culprit
};

int main(int argc, char* argv[]) {
  Derived d1;
  Derived d2(42);
  Derived d3(42, 3.14);
}

That is, until the line marked by the comment is added; because then all hell breaks loose:

> g++ -std=c++11 -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18:11: error: no matching function for call to ‘Derived::Derived()’
   Derived d1;
           ^
test.cpp:18:11: note: candidates are:
test.cpp:13:16: note: Derived::Derived(int)
    using Base::Base;
                ^
test.cpp:13:16: note:   candidate expects 1 argument, 0 provided
test.cpp:13:16: note: Derived::Derived(int, double)
test.cpp:13:16: note:   candidate expects 2 arguments, 0 provided

It seems as if deleting the copy constructor also somehow made the default constructor from Base inaccessible. Googling the problem didn't bring up anything useful; SO suggested this issue, but as far as I understand, I do not use copy initialization in this snippet. Could someone shed some light on what has happened here?

(The compiler that generated the message above is GCC 4.8.2; however, clang returns a similar error message.)

like image 537
David Nemeskey Avatar asked Oct 05 '15 17:10

David Nemeskey


2 Answers

The problem is that marking a copy constructor with delete makes it user-declared, which in effect deletes the default constructor of that class (in your case Derived). The behaviour can be seen in this simple code:

struct X
{
    X(const X&) = delete; // now the default constructor is not defined anymore
};

int main() 
{
    X x; // cannot construct X, default constructor is inaccessible 
}

As a side remark: even if Base::Base() would be inherited, the compiler would see it like Derived(): Base(){}. But Derived is deleted, so it cannot really call Base::Base(). In general, a using Base::Base statement is just syntactic sugar for the corresponding compiler-generated Derived(params): Base(params){}.

like image 85
vsoftco Avatar answered Sep 19 '22 16:09

vsoftco


Whenever you define a custom constructor you need to provide a default constructor explicitly. I.e.

Derived::Derived() = default;
like image 25
SergeyA Avatar answered Sep 16 '22 16:09

SergeyA