c++ array of templated abstract-base-class without breaking strict-aliasing rule - c++

What is the best way to create an array of objects derived from an abstract template base class without violating the strict-aliasing rule. Each derived object will define the template arguments of the base class differently but only through the constant enum value. Here is an example
enum BlaEnum
{
Bla1,
Bla2,
Bla3
};
template <class T, BlaEnum bla = Bla1>
class A
{
public:
virtual void Foo() = 0;
T att;
BlaEnum bll;
};
class B : public A<int, BlaEnum::Bla2>
{
public:
void Foo() override;
};
class C : public A<int, BlaEnum::Bla3>
{
public:
void Foo() override;
};
int main(void)
{
B b;
C c;
//violates strict-aliasing rule
A<int>* BaseArr[2] = { (A<int>*)&b,(A<int>*)&c };
}

The problem here is that class B : public A<int, BlaEnum::Bla2> and class C : public A<int, BlaEnum::Bla3> derive from different A that are not compatible with each other. Each of those classes causes the instantiation of a new template class (neither of which are compatible with A<int>).
In order to have valid common base you require a base class that does not differ in any template parameters (or is a non-template class) from the derived classes.
Modifying your example e.g.:
template <class T>
class Base
{
public:
virtual void Foo() = 0;
};
template <class T, BlaEnum bla = Bla1>
class A : public Base<T>
{
public:
T att;
BlaEnum bll;
};
// B and C are unchanged
int main()
{
B b;
C c;
// Array of pointers to common base class
Base<int>* BaseArr[2] = { &b,&c };
}
One more note: C-style arrays are not a good practice, you should prefer std::array(or std::vector) and smart pointer over raw pointers

Related

Initialization of static template member in CRTP

I try to initialize a static member of a CRTP base class. The base class holds a static template member of the derived class, while the derived class defines other data members. I want to statically initialize this variable. In code, a minimal example would be the following:
template<typename DERIVED>
class base {
public:
static DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
};
int base<derived>::x {0};
int main()
{}
However, the above does not compile, but gives the error message error: specializing member 'base<derived>::x' requires 'template<>' syntax.
How can I get the static initialization to work?
The correct syntax is:
template <class T>
class base {
public:
static T x;
};
template <class T>
T base<T>::x{};
Note that you can't initialize x to a specific integer value, since then your base class won't compile when DERIVED is e.g. an std::string.
You probably also want your inheritance to be explicitly public or private. I.e.:
class derived : public base<derived> {
public:
int a;
};
Edit: To specialize x and it's initialization for specific types T, you have to specialize base itself. I.e.:
class A;
template <>
class base<A> {
public:
static int x;
};
// Note missing "template <>" here.
int base<A>::x{ 5 };
class A : public base<A> { };
This seems rather cumbersome, since you need to already forward declare A in this case before declaring the specialization. To me it feels you might want to rethink your design. Is this really required or is there a simpler way to accomplish what you want?
I have found the static initializer trick, which works in the above setting, too. It was described here and here. In the above context, it would be as follows:
#include <iostream>
template<typename DERIVED>
class base {
public:
static inline DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
struct static_initializer {
static_initializer()
{
derived::x.a = 1;
}
};
static inline static_initializer static_initializer_;
};
int main()
{
std::cout << derived::x.a << "\n";
}
The above output the value 1.
Note: this works with C++17.

How to refer derived class in template member?

The code below won't compile:
struct Base
{
std::vector<void(Base::*)(void)> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
Is it possible to refer derived class in template member x? In the example above I specify exactly Base and derived classes cannot push their own member functions into vector x.
Casting is bad since your code have to assume that this will be called only for instance of Derived class. This means that you either have to assume that all items in x are instance of Derived (in such case declaration of x is to general and should be changed to std::vector<void(Derived::*)(void)> x;) or you have to maintain extra information what which class method is stored in specific position of x. Both approaches are bad.
In modern C++ it is much better do do it like this:
struct Base
{
std::vector<std::function<void()>> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back([&d](){ d.foo(); });
Another good approach can be CRTP:
template<class T>
struct Base
{
std::vector<void(T::*)(void)> x;
};
struct Derived : public Base<Derived>
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
You may, but there is no implicit conversion; it requires a cast.
Derived d;
d.x.push_back(static_cast<void(Base::*)()>(&Derived::foo));
The caveat is the if you use that pointer to member with an object that isn't really a Derived, the behavior is undefined. Tread carefully.
As an addendum, if you want to get rid of the cast when taking the pointer, you can do that by encapsulating the push (with some static type checking to boot):
struct Base
{
std::vector<void(Base::*)(void)> x;
template<class D>
auto push_member(void (D::* p)()) ->
std::enable_if_t<std::is_base_of<Base, D>::value> {
x.push_back(static_cast<void(Base::*)()>(p));
}
};
I think I would express this by calling through a non-virtual member function on the base.
example:
#include <vector>
struct Base
{
std::vector<void(Base::*)(void)> x;
// public non-virtual interface
void perform_foo()
{
foo();
}
private:
// private virtual interface for the implementation
virtual void foo() = 0;
};
struct Derived : public Base
{
private:
// override private virtual interface
void foo() override {}
};
// ...
int main()
{
Derived d;
d.x.push_back(&Base::perform_foo);
auto call_them = [](Base& b)
{
for (auto&& item : b.x)
{
(b.*item)();
}
};
call_them(d);
}

Saving template information in Subclass

I have a parent-class with a function. In this function I want to call a template method but the type of the template depends on the type of sub-class. So I want to save the information about T there. I can't call foo with a template because it's from another part of the Program wich i can't change
class A
{
//this will be called on an instance of B or C, A will never be
//instantiated
void foo()
{
ba<T>();
}
}
class B :public A
{
//T want to save here the Type of T so i won't have to call foo() with
//a template
}
class C :public A
{
//here comes another Type for T
}
What you need is a CRTP pattern, which is very common in C++ template programming.
template<class T>
void ba() {}
template<class Derived>
struct A
{
void foo() {
ba<typename Derived::MyT>();
}
};
struct B
: public A<B>
{
using MyT = int;
};
struct C
: public A<C>
{
using MyT = double;
};
int main() {
B b;
b.foo();
C c;
c.foo();
}
You will need to add a template parameter to the base class A and then specify the type in the declaration of B and C. See the example below:
template <typename T>
class A
{
public:
void foo()
{
ba<T>();
}
};
class B : public A<int>
{
};
class C : public A<bool>
{
};
int main()
{
B b;
C c;
b.foo(); // This calls ba<int>()
c.foo(); // This calls ba<bool>()
return 0;
}
It might be good to spend some time reviewing how templates and inheritance work.
Inheritance
Templates

Conditionally inherit from pure base class

Suppose I have the following class definitions
struct base {
virtual int f() = 0;
};
struct A: public base {
int f() final { return 1; }
};
struct B: public base {
int f() final { return 2; }
};
Is it possible to turn A and B into templates that take a bool parameter that specifies whether to inherit from the base or not? I have usage cases that do or don't require a base class providing a common interface.
Assume that A and B have a lot of member functions, so duplicating implementation would be tedious. But sizeof(A) and sizeof(B) are small.
Sure:
template <bool> struct A
{
// ...
};
template <> struct A<true> : base
{
// ...
};
(Note that you could make A<true> derive from A<false> if that avoids redundancy.)
For example:
template <bool> struct A
{
void f() { std::cout << "A::f called\n"; }
};
template <> struct A<true> : A<false>, base
{
void f() override { A<false>::f(); }
};
int main()
{
A<false> a1;
A<true> a2;
a1.f();
a2.f();
static_cast<base&>(a2).f();
}
I came up with the more direct approach I was looking for, without code duplication.
struct base {
virtual int f() = 0;
};
struct empty_base { };
template <bool Inherit>
struct A final: public std::conditional_t<Inherit,base,empty_base> {
int f() { return 1; }
};
Since you are using a pure base class the distinction shouldn't be important as your optimizer will avoid the virtual function call when you call A::f() since there will never be a derived class that implements a different version of f().
Also you can instead do class A final : base if you don't plan on inheriting from A to avoid having to add final to each function.

Class reference another two classes

I have two classes with some methods with same name.
Can I create third class that accept reference from ony of the other two and in the constructor to set obj variable to A or B type?
class A
{
public:
A();
void f();
};
class B
{
public:
B();
void f();
};
class C
{
public:
C(B&);
C(A&);
??? obj;
};
Maybe you want a template class:
template <typename T>
class C
{
T& obj;
public:
explicit C(T& t) : obj(t) {}
void f() { obj.f(); }
};
And then:
A a;
B b;
C<A> c1(a);
C<B> c2(b);
c1.f();
c2.f();
C++ is a very flexible language and as such provides multiple options for what you are asking for. Each with their own pros and cons.
The first route that comes to mind is to use polymorphism.
You have two routes to choose from: static or dynamic polymorphism.
The Static Polymorphic Route
To use static polymorphism (also known as compile-time polymorphism) you should make C a template class:
template <typename T> class C
{
public:
C(T&);
T& obj;
}
The Dynamic Polymorphic Route
To use dynamic (also known as run-time polymorphism) you should provide an interface:
class Fer
{
public:
virtual ~Fer() {}
virtual void f() = 0;
}
Which A and B would implement:
class A : public Fer
{
public:
A();
void f() overide;
};
class B : public Fer
{
public:
B();
void f() overide;
};
C would then be like this:
class C
{
public:
C(Fer&);
Fer& obj;
}
The Variant Route
There are various libraries that provide classes that can safely hold arbitrary types.
Some examples of these are:
Boost.Any
Boost.Variant
QVariant from Qt
When using such classes you generally need some means of converting back to the actual type before operating on it.
You can have a base class that defines the required interface.
class Base
{
public:
Base();
virtual void f();
};
And you can have derived classes that implement the interface.
class A : public Base
{
public:
A();
virtual void f();
};
class B : public Base
{
public:
B();
virtual void f();
};
The class C then refers to the Base class and can actually accept objects of A or B type.
class C
{
private:
Base& base;
public:
C(Base& b) : base(b) {}
};
It can be easily used then.
int main()
{
B b;
C c(b);
return 0;
}