How to define generic template signature - c++

I have 2 classes where the functions are copy and paste. The only difference between these classes is class each inherit. These super classes have same call signatures, but the constructors are different.
I was trying to do something like:
template<class BaseClass>
class IGenericPart : public BaseClass {
public:
int commonCall1() { return 10; }
int commonCall2() { return 44; }
};
class A : public IGenericPart<RealBaseClass1> {
public:
A(int x) : IGenericPart<RealBaseClass1> (x, b) {}
};
class B : public IGenericPart<RealBaseClass2> {
public:
B(string z) : IGenericPart<RealBaseClass2> (z, anothertype2, anothertype2) {}
};
But I don't know how to make the IGenericPart class having a forward constructor based on the generic BaseClass.
So basically, I need that the IGenericPart<RealBaseClass1> and IGenericPart<RealBaseClass2> having different constructors.

You're just missing a using declaration.
When class IGenericPart<> inherits from BaseClass it does not automatically inherit the constructors from BaseClass. To inherit constructors, you must do so explicitly with a using declaration, like so:
template<class BaseClass>
class IGenericPart : public BaseClass {
public:
using BaseClass::BaseClass;
// etc ...
};
This then creates constructors for IGenericPart<BaseClass> that are in correspondence with and which forward to each constructor of BaseClass, so the initialization lists of A and B will work as expected.
Note that constructor inheritence is a C++11 feature, so you must be compiling in C++11 mode with a compiler that supports C++11 for this to work.

If you can't use c++11 for some reasone you can get it to work by adding the following, clunky bits, to IGenericPart:
template<class BaseClass>
class IGenericPart: public BaseClass {
public:
template <typename A>
IGenericPart(A a) : BaseClass(a) {}
template <typename A, typename B>
IGenericPart(A a, B b) : BaseClass(a, b) {}
template <typename A, typename B, typename C>
IGenericPart(A a, B b, C c) : BaseClass(a, b, c) {}
}

Related

C++ Cannot construct class that extends template [duplicate]

Why does this code:
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
};
int main(void)
{
B *b = new B(5);
delete b;
}
Result in these errors:
main.cpp: In function ‘int main()’:
main.cpp:13: error: no matching function for call to ‘B::B(int)’
main.cpp:8: note: candidates are: B::B()
main.cpp:8: note: B::B(const B&)
Shouldn't B inherit A's constructor?
(this is using gcc)
If your compiler supports C++11 standard, there is a constructor inheritance using using (pun intended). For more see Wikipedia C++11 article. You write:
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
using A::A;
};
This is all or nothing - you cannot inherit only some constructors, if you write this, you inherit all of them. To inherit only selected ones you need to write the individual constructors manually and call the base constructor as needed from them.
Historically constructors could not be inherited in the C++03 standard. You needed to inherit them manually one by one by calling base implementation on your own.
For templated base classes, refer to this example:
using std::vector;
template<class T>
class my_vector : public vector<T> {
public:
using vector<T>::vector; ///Takes all vector's constructors
/* */
};
Constructors are not inherited. They are called implicitly or explicitly by the child constructor.
The compiler creates a default constructor (one with no arguments) and a default copy constructor (one with an argument which is a reference to the same type). But if you want a constructor that will accept an int, you have to define it explicitly.
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
public:
explicit B(int x) : A(x) { }
};
UPDATE: In C++11, constructors can be inherited. See Suma's answer for details.
This is straight from Bjarne Stroustrup's page:
If you so choose, you can still shoot yourself in the foot by inheriting constructors in a derived class in which you define new member variables needing initialization:
struct B1 {
B1(int) { }
};
struct D1 : B1 {
using B1::B1; // implicitly declares D1(int)
int x;
};
void test()
{
D1 d(6); // Oops: d.x is not initialized
D1 e; // error: D1 has no default constructor
}
note that using another great C++11 feature (member initialization):
int x = 77;
instead of
int x;
would solve the issue
You have to explicitly define the constructor in B and explicitly call the constructor for the parent.
B(int x) : A(x) { }
or
B() : A(5) { }
How about using a template function to bind all constructors?
template <class... T> Derived(T... t) : Base(t...) {}
Correct Code is
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
public:
B(int a):A(a){
}
};
main()
{
B *b = new B(5);
delete b;
}
Error is b/c Class B has not parameter constructor and second it should have base class initializer to call the constructor of Base Class parameter constructor
Here is how I make the derived classes "inherit" all the parent's constructors. I find this is the most straightforward way, since it simply passes all the arguments to the constructor of the parent class.
class Derived : public Parent {
public:
template <typename... Args>
Derived(Args&&... args) : Parent(std::forward<Args>(args)...)
{
}
};
Or if you would like to have a nice macro:
#define PARENT_CONSTRUCTOR(DERIVED, PARENT) \
template<typename... Args> \
DERIVED(Args&&... args) : PARENT(std::forward<Args>(args)...)
class Derived : public Parent
{
public:
PARENT_CONSTRUCTOR(Derived, Parent)
{
}
};
derived class inherits all the members(fields and methods) of the base class, but derived class cannot inherit the constructor of the base class because the constructors are not the members of the class. Instead of inheriting the constructors by the derived class, it only allowed to invoke the constructor of the base class
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
B(int x):A(x);
};
int main(void)
{
B *b = new B(5);
delete b;
}

How to enforce implementing the constructor of a specific data type on a derived class?

Given an abstract class A and a data type T, is there a way to enforce implementing a constructor of T on a derived class of A? i.e.
class A {
public:
virtual ~A() {}
virtual void foo() = 0;
};
class B : public A {
public:
B(T t) { ... } // this constructor must be implemented otherwise compilation will error out
};
It is possible with a private token based design. This idea looks something like the following:
#include <utility>
#include <memory>
class A{
private:
struct create_token
{
create_token(const create_token &) = delete;
create_token& operator=(const create_token &) = delete;
create_token(create_token &&) = default;
create_token& operator=(create_token &&) = default;
friend class A;
private:
create_token(){};
};
inline static auto token = create_token{};
protected:
A(create_token) {}
public:
template<class T, typename... ARGUMENTS>
static std::unique_ptr<T> create(ARGUMENTS&&... arguments)
{
// Whatever creation mechanism here
return std::make_unique<T>(create_token{}, std::forward<ARGUMENTS>(arguments)...);
}
};
class B : public A {
public:
template <typename Token> // Can't name A::create_token, it is private
B(Token tok) : A(std::move(tok)) {}
B(){} // Will always lack a `create_token`
};
The example needs a bit of modification for your case (mainly to restrict the constructor) - but the point is that construction can only go through the factory create function.
If A will have it's own constructor which takes parameter and no default constructor
class A {
public:
A(T t) {};
virtual ~A() {}
virtual void foo() = 0;
};
Then all derived classes have to initialize that in their constructor, which means at least one constructor will be needed.
See below examples:
class B : public A {
public:
B(T t):A(t) { ... } // pass parameter to A constructor
};
class C : public A {
public:
C(): A(T{}) { ... } // initialize A with a default T
};
class D : public A {
public:
using A::A; // inherit A's constructors
};
class E : public A {
public:
//error - doesn't work without any constructor!
};
You shouldn't try to force any constructor syntax in derived classes - they may know things which you don't know and they may or may not need T. I'm not sure if forcing constructor signature is even possible.
My best shot would be using CRTP, so that you can check the properties of the derived class within the base class:
template <class Derived>
class A_CRTP //: public A_Base
{
protected:
A() {
static_assert(sizeof(Derived{T}) > 0, "Constructor from T not present");
}
};
class B : public A_CRTP<B> {
public:
B();
B(T); // removing this is a compile-time error.
};
However, this is trivially bypassed:
class C : public B
{
C();
// No C(T) needed, B has that and A doesn't know about C.
};
https://godbolt.org/z/qzd_LJ
That makes this whole exercise somewhat pointless, as it just forces users to take extra steps before they can write the set of constructors they want (see answer of #Yksisarvinen).

Overloading inherited constructors

Given the following base class:
class Base {
int a, b;
public:
Base(int a, int b=42): a(a), b(b) { }
};
And a class that is derived from base:
class Derived: public Base {
using Base::Base; // inherit Base constructors
bool c;
public:
Derived(int a): Base(a), c(true) { }
Derived(int a, int b): Base(a, b), c(true) { }
};
Is there a way to avoid having to create two separate constructors for Derived and instead overload the inherited Base constructors to initialize the extra member of Derived?
I was thinking to use something like this:
template <typename... Args,
typename std::enable_if_t<std::is_constructible_v<Base, Args&&...>, int> = 0>
explicit Derived(Args&&... args):
Base(std::forward<Args>(args)...), c(true) {}
This is close, but is too verbose and does not work if the the base class's constructors are inherited. i.e. if using Base::Base is present in the class (then it defaults to those constructors and does not initialize the field b).
It works if the base class inherited constructors are not present i.e. removing using Base::Base.
Is this the only way to have this work? i.e. by removing using Base::Base and using a variadic template constructor in each derived class? Is there a less verbose way to overload the inherited constructors?
I am using C++17.
In this case all you need to do is provide c with an in class initializer
class Derived : public Base {
using Base::Base;
bool c = true;
};
allows you to use Base's constructors and will initialize c to true in all cases.
It seems like what you're looking for is a way to inherit Base's constructors while just initializing members of Derived to something specific. For that, we can use a default member initializer:
class Derived: public Base {
public:
using Base::Base;
private:
bool c = true;
};
Constructing a Derived(42) will invoke the Base(int) constructor, but also initialize c to true.

Template class with two types, inheritance and forward declaration

I'm wrapping my head around this problem. I think it's actually not possible to do, but just to be sure I'd like to ask here if there actually is a solution.
Consider the following code. There are 2 templated classes A and B and two non-templated classes C and D which derive from A and B respectively.
// definition of class A
template <class DerivedA, class DerivedB> class A {
private:
DerivedB data;
public:
A(const DerivedB& data) : data(data) {}
virtual ~A() {}
DerivedB get() const { return data; }
};
// definition of class B
template <class DerivedA, class DerivedB> class B {
private:
DerivedA data;
public:
B(const DerivedA& data) : data(data) {}
virtual ~B() {}
DerivedA get() const { return data; }
};
// forward declaration of D
class D;
// definition of class C, derives from A<C, D>
class C : public A<C, D> {
private:
int extraInfo;
public:
C(const D& d) : A(d) {}
virtual ~C() {}
int getExtraInfo() const { return extraInfo; }
};
// definition of class D, derives from B<C, D>
class D : public B<C, D> {
private:
int extraInfo;
public:
D(const C& c) : B(c) {}
virtual ~D() {}
int getExtraInfo() const { return extraInfo; }
};
The problem here is that class C cannot be defined because class D is only forward declared. Hence, when the template A is written out then it doesn't know what its type for its private member is. Note that I cannot work with pointers, I need some known functionality. Is it in any way possible to compile such that I have my classes C and D?
There is no way around this problem as you explain it and there should not be. As you have it now:
class C : public A<C, D>
means that C will inherit a data member of type D. In turn:
class D : public B<C, D>
means that D will inherit a data member of type C.
If C has a D, which has a C, which has a D... you have a nice infinite recursion, meaning in this case that the size of any C or D object will be infinite.
So, unless you use pointers (you can cut the infinite chain at any point inserting an appropriate null pointer) or references (you can reference a previously used object), you cannot and should not have this kind of classes.
C inherits a member of type D, D inherits a member of type C. So, no, it's not possible.
You can get away with this by making C and D implement a pure-virtual class, with the functionality you need (including getters), and making them pass that class as a template argument. You then do actually use a pointer to it in A and B, but you keep all the functionality.
Something like this (make your own adaptations)
// definition of class A
template <class DerivedA, class DerivedB> class A {
private:
const DerivedB& _data;
public:
A(const DerivedB& data) : _data(data) {}
virtual ~A() {}
DerivedB& get() const { return data; }
};
// definition of class B
template <class DerivedA, class DerivedB> class B {
private:
DerivedA data;
public:
B(const DerivedA& data) : data(data) {}
virtual ~B() {}
DerivedA get() const { return data; }
};
class TheInterface {
public:
virtual int getExtraInfo() const = 0;
virtual ~TheInterface() = 0;
};
// definition of class C, derives from A<C, D>
class C : public TheInterface, public A<C, TheInterface> {
private:
int extraInfo;
public:
C(const TheInterface& d) : A(d) {}
virtual ~C() {}
int getExtraInfo() const { return extraInfo; }
};
// definition of class D, derives from B<C, D>
class D : public TheInterface, public B<C, D> {
private:
int extraInfo;
public:
D(const C& c) : B(c) {}
virtual ~D() {}
int getExtraInfo() const { return extraInfo; }
};

Calling function with two template parameters

I am having a problem calling a template function with two template arguments.
I have a class and the class accepts objects of two different types. I don't know the types yet, so I left them as template parameters. I then store the objects in wrapper classes. In the end I want to be able to call a templated function with two template arguments, that takes my two objects. But I am perplexed at how to do this.
Here is a stripped down version of the code to explain my problem.
template<typename A, typename B>
void someTemplateFunction(A a, B b);
class Problem
{
private:
class WrapperA
{
public:
virtual void doSomething() = 0;
};
template<typename A>
class ConcreteWrapperA : public wrapperA
{
private:
A a;
public:
ConcreteWrapperB(A b_) : a(a_) {}
virtual void doSomething();
};
class WrapperB
{
public:
virtual void doSomething() = 0;
};
template<typename B>
class ConcreteWrapperB : public wrapperB
{
private:
B b;
public:
ConcreteWrapperB(B b_) : b(b_) {}
virtual void doSomething();
};
WrapperA *a;
WrapperB *b;
public:
template<typename A>
void setA(A a)
{
a = new ConcreteWrapperA<A>(a);
}
template<typename B>
void setB(B b)
{
a = new ConcreteWrapperB<B>(b);
}
void call_someTemplateFunction(); // ??????? How do i do this?
};
The problem is that you've type-erased both types A and B separately, so there's nowhere in the translation of your code that both types A and B are known.
If you can write a single function template<typename A, typename B> void set(A, B) then you could capture the pair type <A, B> at that point.
Alternatively, would it be possible for someTemplateFunction to operate without knowing both types A and B at the same time?
This is an issue fundamental to the design of C++ as a single-pass, separate compilation language.
Suppose that your program has three compilation units; A.cpp calls setA with a range of types T[A], B.cpp calls setB with another range of types T[B], and C.cpp owns the Problem object and wants to call someTemplateFunction. Then there's no time during compilation when the compiler knows both the range of types in A.cpp and the range of types in B.cpp, so it can't instantiate someTemplateFunction with the appropriate cross-product T[A] x T[B].