Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing inherited constructor from the base class with a custom construcutor

Given the following example:

struct tag1 { };
struct tag2 { };

template<typename T>
class Base {
public:
  Base(T /*value*/) { }
  Base(tag1) { }
};

template<>
class Base<void> {
public:
  Base() { }
  Base(tag1) { }
};

template<typename T = void>
class MyClass : public Base<T> {
public:
  using Base<T>::Base;

  MyClass(tag2) : Base<T>(tag1{}) { }
};

int main() {
  {
    MyClass<> defaultConstructible;
    MyClass<> tagConstructible(tag2{});
  }
  {
    MyClass<int> valueConstructible(0);
    MyClass<int> tagConstructible(tag2{});
  }
}

The class MyClass can be parameterized with any types, it shall be default constructible when the type T equals void, otherwise it is constructible from a type T as written in the main function.

I'm using a parameter dependent base class to get this behaviour (through using the constructor of the base class).

Also I need to add constructors to the class hierarchy which accept other parameters, as you see in the example source (tag structs).

Is it possible to do this without declaring all constructors in the same class? Because mixing the superclass constructors with custom ones will yield the following error message:

main.cpp: In function 'int main()':
main.cpp:30:15: error: no matching function for call to 'MyClass<>::MyClass()'
     MyClass<> defaultConstructible;
               ^~~~~~~~~~~~~~~~~~~~
main.cpp:22:18: note: candidate: MyClass<>::MyClass(tag1)
   using Base<T>::Base;
                  ^~~~
main.cpp:22:18: note:   candidate expects 1 argument, 0 provided
main.cpp:25:3: note: candidate: MyClass<T>::MyClass(tag2) [with T = void]
   MyClass(tag2) : Base<T>(tag1{}) { }
   ^~~~~~~
main.cpp:25:3: note:   candidate expects 1 argument, 0 provided
main.cpp:20:7: note: candidate: constexpr MyClass<>::MyClass(const MyClass<>&)
 class MyClass : public Base<T> {
       ^~~~~~~
main.cpp:20:7: note:   candidate expects 1 argument, 0 provided
main.cpp:20:7: note: candidate: constexpr MyClass<>::MyClass(MyClass<>&&)
main.cpp:20:7: note:   candidate expects 1 argument, 0 provided

Demo

like image 205
Denis Blank Avatar asked Oct 31 '22 02:10

Denis Blank


1 Answers

Once you introduce your own constructor, the default constructor will not get implicitly defined - it doesn't matter that you're trying to inherit it.

You can simply explicitly define the default constructor as defaulted:

template<typename T = void>
class MyClass : public Base<T> {
public:
  using Base<T>::Base;

  MyClass() = default;
  MyClass(tag2) : Base<T>(tag1{}) { }
};

Here, MyClass<> becomes default constructible, but MyClass<int> still isn't because Base<int> isn't.

like image 110
Barry Avatar answered Nov 02 '22 11:11

Barry