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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With