Iterate over different CRTP Derived class methods - c++

In an example below I have a pretty typical CRTP example, two different derived classes that both have a method bar. The base class has a method foo which just forwards to some derived bar method
#include <iostream>
template<typename Derived>
class Base {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
class DerivedA : public Base<DerivedA> {
public:
void bar() {
::std::cout << "A\n";
}
};
class DerivedB : public Base<DerivedB> {
public:
void bar() {
::std::cout << "B\n";
}
};
int main() {
DerivedA a;
DerivedB b;
a.foo();
b.foo();
}
It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?

You can use Boost.Variant. For example:
typedef boost::variant<DerivedA, DerivedB> Derived;
struct BarCaller : public boost::static_visitor<void> {
template <class T>
void operator()(T& obj) {
obj.bar();
}
};
int main() {
std::vector<Derived> vec{DerivedA(), DerivedB(), DerivedA()};
BarCaller bar;
for (Derived& obj : vec) {
obj.apply_visitor(bar);
}
}
This lets you store heterogeneous types in a vector or other STL container (by using a "discriminated union"), and lets you call a specific function on all of them regardless of their not having a common ancestor or any virtual methods.

It doesn't seem like I can have an array / vector / etc. of the base class because it would have to have a type along the lines of Base<T> where T is different.
You can have a base class of Base<T> for all T, then, you can have a list/vector/array of pointers to the base class, if that works for you.
struct BaseOne
{
virtual void foo() = 0;
virtual ~BaseOne() {}
};
template<typename Derived>
class Base : struct BaseOne {
public:
void foo() {
static_cast<Derived*>(this)->bar();
}
};
and then,
int main() {
std::vector<BaseOne*> v {new DerivedA, new DerivedB };
for ( auto item : v )
item->bar();
for ( auto item : v )
delete item;
}
Is there some kind of convention without virtual for being able to iterate over different derived classes assuming they all have the same method (bar in this case)?
No, there isn't.

As per now, variant has became part of the C++17 standard and the solution to the problem can be solved by std::variant and std::visit as follows.
The template class in the example is Interface<> and use the CRTP idiom to force derived class to implement helloImpl():
#include <iostream>
#include <vector>
#include <variant>
template<typename Implementer>
struct Interface {
void hello() const {
static_cast<Implementer const *>(this)->helloImpl();
}
};
A couple of class examples with different implementations of helloImpl()
struct Hello1 : public Interface<Hello1> {
void helloImpl() const {
std::cout << "Hello1" << std::endl;
}
};
struct Hello2 : public Interface<Hello2> {
void helloImpl() const {
std::cout << "Hello2" << std::endl;
}
};
And here is how to use it to store data in a vector<> container and its traversal:
int main() {
using var_t = std::variant<Hello1, Hello2>;
std::vector<var_t> items{Hello1(), Hello1(), Hello2()};
for(auto &item: items) {
std::visit([](auto &&arg) {
arg.hello();
}, item);
}
return 0;
}

Related

C++ - Pushing variadic template class object into vector

class Base
{
public:
virtual void foo() = 0;
};
class A : public Base
{
public:
void foo() override { std::cout << "A\n"; }
};
class B : public Base
{
public:
void foo() override { std::cout << "B\n"; }
};
class Registry
{
public:
static Registry& instance()
{
static Registry s_instance;
return s_instance;
}
void register_foo(Base* foo)
{
m_vec.emplace_back(foo);
}
private:
std::vector<Base*> m_vec;
};
template<typename ... T>
class Foo : public T...
{
public:
Foo()
{
Registry::instance().register_foo(this);
}
void test() { (T::foo(), ...); }
};
int main()
{
auto f1 = std::make_unique<Foo<A, B>>();
auto f2 = std::make_unique<Foo<A>>();
f1->test();
f2->test();
}
As you can see I have a Base class, class A and class B.
A and B inherit from Base.
Class Foo is a template class, which is with a variadic template.
The idea is to be able to pass class A and class B into Foo.
Then this Foo is registered in the Registry class / pushed into a vector.
The problem is the following - as you can see I can have both Foo<A> and Foo<A, B>, or Foo<B, A>.
How can I have such a vector which can accept all possible types of Foo?
How about a simple common base class?
class FooBase {
public:
virtual ~FooBase() {}
virtual void test() = 0;
};
template<typename... T>
class Foo : public FooBase, public T...
{
public:
Foo() { }
void test() override { (T::foo(), ...); }
};
int main()
{
auto f1 = std::make_unique<Foo<A, B>>();
auto f2 = std::make_unique<Foo<A>>();
std::vector<std::unique_ptr<FooBase>> foos;
foos.push_back(std::move(f1));
foos.push_back(std::move(f2));
}
A std::vector holds one type of objects. You cannot put objects of different types into the same vector (and objects created from a template with different template arguments are different types).
One option (I'd not recommend it) is having a vector that holds instances of std::any) - works, but cumbersome and inefficient to work with. Another option is a vector of pointers to a common base class and taking advantage of polymorphism. A third option is simply having sepperate vectors for each type of object.

Convert class to derived class, without modifying it

I am working with a set of classes A, B, ... These classes are independent except that they have one method in common. Now I want to combine these classes in a vector, to call method in one loop. It seems that the best solution is to make the classes derived classes from some Parent (see below).
Now the question is the following. I want to create a header-only library for each class (a.h, b.h, ...). There I want the classes to be completely independent. Only in the main module I want to 'attach' the classes to a Parent to be able to combine them in a vector. How do I do this? Or do I have to resort to a vector of void* pointers? Or is there another way to combine these classes in a vector?
Classes in list: with parent/child paradigm
Here is what I have been able to do to combine the classes in the vector. Note I specifically want to avoid the parent/child paradigm in the class definitions. But I still want to combine them in a vector.
#include <iostream>
#include <vector>
#include <memory>
class Parent
{
public:
virtual ~Parent(){};
virtual void method(){};
};
class A : public Parent
{
public:
A(){};
~A(){};
void method(){};
};
class B : public Parent
{
public:
B(){};
~B(){};
void method(){};
};
int main()
{
std::vector<std::unique_ptr<Parent>> vec;
vec.push_back(std::unique_ptr<Parent>(new A));
vec.push_back(std::unique_ptr<Parent>(new A));
vec.push_back(std::unique_ptr<Parent>(new B));
for ( auto &i: vec )
i->method();
return 0;
}
Compile using e.g.
clang++ -std=c++14 main.cpp
A possible solution based on type erasure, static member functions and pointers to void that doesn't make use of virtual at all (example code, far from being production-ready):
#include <iostream>
#include <vector>
struct Erased
{
using fn_type = void(*)(void *);
template<typename T>
static void proto(void *ptr) {
static_cast<T*>(ptr)->method();
}
fn_type method;
void *ptr;
};
struct A
{
void method(){ std::cout << "A" << std::endl; };
};
struct B
{
void method(){ std::cout << "B" << std::endl; };
};
int main()
{
std::vector<Erased> vec;
vec.push_back(Erased{ &Erased::proto<A>, new A });
vec.push_back(Erased{ &Erased::proto<B>, new B });
for ( auto &erased: vec ) {
erased.method(erased.ptr);
}
return 0;
}
This can help to avoid using a common base class. See it on wandbox.
As mentioned in the comments, here is a slightly modified version that adds create and invoke methods to reduce the boilerplate for the users.
This is more of a pseudocode, trivial details are omitted.
struct HolderBase
{
virtual void foo() = 0;
};
template <class T>
struct Holder : HolderBase
{
Holder(T* t) : t(t) {}
T* t;
void foo() { t->foo(); }
};
std::vector<HolderBase*> v { new Holder<A>(new A), new Holder<B>(new B) };
You can also have a variant of Holder that holds an object by value (and mix both variants in the same vector freely).
If you have a single method to call, there is a much simpler solution:
A a;
B b;
std::vector<std::function<void()> v { [](){a.foo();}, [](){b.foo();} };
You want to erase the type of the objects and treat them uniformly, so naturally type erasure is the solution.
class with_method_t {
struct model_t {
virtual ~model_t() = default;
virtual void call_method() = 0;
};
template<class C>
class concept_t final : public model_t {
C obj;
public:
concept_t(C const& c) : obj{c} {}
concept_t(C&& c) : obj{std::move(c)} {}
void call_method() override { obj.method(); }
};
std::unique_ptr<model_t> instance;
public:
template<class C>
with_method_t(C&& arg)
: instance{std::make_unique<concept_t<C>>(std::forward<C>(arg))}
{}
void method() { instance->call_method(); }
};
Then have yourself a vector of with_method_t which is a value type. No raw dynamic allocation or de-allocation. The instance is build by forwarding the argument it receives into a small polymorphic container:
std::vector<with_method_t> vec;
vec.emplace_back(A{});
vec.emplace_back(B{});
for ( auto &i: vec )
i.method();

overriding the template base method in derived class?

Suppose I have a base class as below:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
then, I create a Derived class as below, and override the do_something() method:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
I know virtualization does not work in class templates, and I am just hiding the implementation of the methods. but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
my question is, given that static_cast of Derived class to base class gives me the do_something of based class, Is there any way that I can store them as base classes while each has their implementation of do_something() class ?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
This is already just not possible in C++. In C++, a vector can only contain objects of the same static type. The only way a vector can contain different types of objects is if their static type is still the same, but they have different dynamic types, but this is type erasure/polymorphism which you said you don't want to use.
I think maybe you need to rethink your requirements, because your question in essence reads: I want to do something, but I don't want to use technique X which is explicitly defined as the only way to do that something in C++!
I did this and it seems to work fine:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
Output:
Base::do_something()
Derived::do_something()
A little variation of the melpomene's answer (adding a no-template base struct, BaseOfBase, for the Base<T> structs) permit the use of a common vector of base of derived classe of different T types.
A working example
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
When we say virtualization doesn't work in template classes, we don't mean that you can't do virtual functions in a template class, nor does it mean that you cannot override a member function with a specialized version of it.
#melpomene showed an example of overriding in general, and I will show here with specialization:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
Which will output
Base::do_something()
10
Derived::do_something()
9
Showing that it perfectly works as expected.
What we do mean when saying that
virtualization does not work in class templates
Basically means that you can't use as a template the derived class when the base is expected.
Consider the above classes Base<T> and Derived, then if we have the following code:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
it will fail because std::unique_ptr<Derived> does not inherit from std::unique_ptr<Base<T>> although Derived itself inherits from Base<T>.

Override template member in Interface

Is it possible to declare some type of base class with template methods which i can override in derived classes? Following example:
#include <iostream>
#include <stdexcept>
#include <string>
class Base
{
public:
template<typename T>
std::string method() { return "Base"; }
};
class Derived : public Base
{
public:
template<typename T>
std::string method() override { return "Derived"; }
};
int main()
{
Base *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
I would expect Derived as the output but it is Base. I assume it is necessary to make a templated wrapper class which receives the implementing class as the template parameter. But i want to make sure.
1) Your functions, in order to be polymorphic, should be marked with virtual
2) Templated functions are instantiated at the POI and can't be virtual (what is the signature??How many vtable entries do you reserve?). Templated functions are a compile-time mechanism, virtual functions a runtime one.
Some possible solutions involve:
Change design (recommended)
Follow another approach e.g. multimethod by Andrei Alexandrescu (http://www.icodeguru.com/CPP/ModernCppDesign/0201704315_ch11.html)
Template methods cannot be virtual. One solution is to use static polymorphism to simulate the behavior of "template virtual" methods:
#include <iostream>
#include <stdexcept>
#include <string>
template<typename D>
class Base
{
template<typename T>
std::string _method() { return "Base"; }
public:
template<typename T>
std::string method()
{
return static_cast<D&>(*this).template _method<T>();
}
};
class Derived : public Base<Derived>
{
friend class Base<Derived>;
template<typename T>
std::string _method() { return "Derived"; }
public:
//...
};
int main()
{
Base<Derived> *b = new Derived();
std::cout << b->method<bool>() << std::endl;
return 0;
}
where method is the interface and _method is the implementation. To simulate a pure virtual method, _method would absent from Base.
Unfortunately, this way Base changes to Base<Derived> so you can no longer e.g. have a container of Base*.
Also note that for a const method, static_cast<D&> changes to static_cast<const D&>. Similarly, for an rvalue-reference (&&) method, it changes to static_cast<D&&>.
Another possible aproach to make your example work as you expect is to use std::function:
class Base {
public:
Base() {
virtualFunction = [] () -> string { return {"Base"}; };
}
template <class T> string do_smth() { return virtualFunction(); }
function<string()> virtualFunction;
};
class Derived : public Base {
public:
Derived() {
virtualFunction = [] () -> string { return {"Derived"}; };
}
};
int main() {
auto ptr = unique_ptr<Base>(new Derived);
cout << ptr->do_smth<bool>() << endl;
}
This outputs "Derived". I'm not sure that this is what you realy want, but I hope it will help you..
I had the same problem, but I actually came up with a working solution. The best way to show the solution is by an example:
What we want(doesn't work, since you can't have virtual templates):
class Base
{
template <class T>
virtual T func(T a, T b) {};
}
class Derived
{
template <class T>
T func(T a, T b) { return a + b; };
}
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
The solution(prints 3HelloWorld0.3):
class BaseType
{
public:
virtual BaseType* add(BaseType* b) { return {}; };
};
template <class T>
class Type : public BaseType
{
public:
Type(T t) : value(t) {};
BaseType* add(BaseType* b)
{
Type<T>* a = new Type<T>(value + ((Type<T>*)b)->value);
return a;
};
T getValue() { return value; };
private:
T value;
};
class Base
{
public:
virtual BaseType* function(BaseType* a, BaseType* b) { return {}; };
template <class T>
T func(T a, T b)
{
BaseType* argA = new Type<T>(a);
BaseType* argB = new Type<T>(b);
BaseType* value = this->function(argA, argB);
T result = ((Type<T>*)value)->getValue();
delete argA;
delete argB;
delete value;
return result;
};
};
class Derived : public Base
{
public:
BaseType* function(BaseType* a, BaseType* b)
{
return a->add(b);
};
};
int main()
{
Base* obj = new Derived();
std::cout << obj->func(1, 2) << obj->func(std::string("Hello"), std::string("World")) << obj->func(0.2, 0.1);
return 0;
}
We use the BaseType class to represent any datatype or class you would usually use in a template. The members(and possibly operators) you would use in a template are described here with the virtual tag. Note that the pointers are necessary in order to get the polymorphism to work.
Type is a template class that extends Derived. This actually represents a specific type, for example Type<int>. This class is very important, since it allows us to convert any type into the BaseType. The definition of the members we described described in BaseType are implemented here.
function is the function we want to override. Instead of using a real template we use pointers to BaseType to represent a typename. The actual template function is in the Base class defined as func. It basically just calls function and converts T to Type<T>. If we now extend from Base and override function, the new overridden function gets called for the derived class.

What is the best way to handle a collection of derived objects in a derived class

Imagine I have a class 'BaseA' that contains a collection of items 'ItemA'.
Now I want to extend 'BaseA' to add extra capabilities, so I derive 'DerivedA' from 'BaseA'.
One characteristic of 'DerivedA' is that it has to handle more sophisticated 'DerivedITemA' items instead of 'ItemA' ones.
class BaseA {
protected:
vector<ItemA> x;
void m1(int i) { x.m1(i); }
};
class ItemA {
protected:
void m1(int i) { ... }
};
class DerivedItemA : public ItemA {
void m2(int i) { ... }
};
Now I would like to handle something of this sort:
class DerivedA : public BaseA {
vector<DerivedItemA> x;
void m2(int i) { x[i].m2(); }
};
I.e. have my Derived class handle derived items. The above definition of x is incorrect as it clashes with the one in BaseA. But the idea is I want to be able to reuse all methods in BaseA that handle x as long as they deal with ItemA elements and have the extended methods in DerivedA to handle the extra intricacies of DerivedItemA type of data
Any suggestion? My current thoughts are in the lines of defining a new datatype for x (VectorOfItemA for instance) and derive from it VectorOfDerivedItemA. I wonder if there is a simpler / better solution.
Thanks
I believe you need to have pointers in your vectors in order to handle this. I'm a little confused what value to pass to m1 and m2 since i appears to be an index, but here's my guess:
class BaseA {
protected:
vector<ItemA*> x;
void m1(int i) { x[i]->m1(i); }
};
class ItemA {
protected:
void m1(int i) { ... }
};
class DerivedItemA : public ItemA {
void m2(int i) { ... }
};
class DerivedA : public BaseA {
vector<DerivedItemA*> y; //don't shadow the base class vector!
void m2(int i) { y[i]->m2(i); }
};
Then, when you add an item in DerivedA, add it to both x and y. That way BaseA can do it's thing to the pointer in x and DerivedA can do its thing on the pointer in y.
Edit: you'll also need to provide a virtual method for adding items otherwise you might get things added to BaseA.x that don't get added to DerivedA.y.
Do you own all the classes? If so, you can refactor into a template base class instead.
template <typename ITEM>
class BaseT {
protected:
vector<ITEM> x;
void m1(int i) { x[i].m1(); }
};
typedef BaseT<ItemA> BaseA;
class DerivedA: public BaseT<DerivedItemA> {
void m2(int i) { x[i].m2(); }
};
If you intend to re-use code that takes BaseA to also accept a DerivedA, then you may need to modify them to be template functions/classes as well.
Otherwise, you will need some kind of "polymorphic" base object for the vector. You can look at Retrieve data from heterogeneous std::list (or my follow up question: unique_ptr member, private copy constructor versus move constructor) for one such approach.
As an alternative to a polymorphic item, you can define an interface for your base.
class BaseI {
protected:
virtual void m1(int) = 0;
//... other interfaces
public:
virtual ~BaseI () {}
//... other public interfaces
};
template <typename ITEM>
class BaseT : public BaseI {
protected:
vector<ITEM> x;
void m1(int i) { x[i].m1(); }
//...implement the other interfaces
};
//...
Now, code that takes a BaseA needs to be refactored to take a BaseI instead. That new code will be able to accept a DerivedA as well.
You may try to use Curiously Recurring Template Pattern - CRTP:
live demo
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;
struct Item
{
void m1(int i)
{
cout << "m1(" << i << ")" << endl;
}
};
struct DerivedItem : Item
{
void m2(int i)
{
cout << "m2(" << i << ")" << endl;
}
};
template<typename Derived>
struct IBase
{
void m1(int i)
{
for(auto &&z : static_cast<Derived*>(this)->x)
{
z.m1(i);
}
}
};
template<typename Derived>
struct IDerivedBase: IBase<Derived>
{
void m2(int i)
{
for(auto &&z : static_cast<Derived*>(this)->x)
{
z.m2(i);
}
}
};
struct Base : IBase<Base>
{
vector<Item> x;
};
struct DerivedBase : IDerivedBase<DerivedBase>
{
vector<DerivedItem> x;
};
int main()
{
Base b;
b.x.resize(3);
DerivedBase d;
d.x.resize(1);
b.m1(11);
d.m1(22);
d.m2(33);
}
Output is:
m1(11)
m1(11)
m1(11)
m1(22)
m2(33)
Vector will contain either all elements as ItamA in BaseA instantiations or all elements of DerivedItemA in DerivedA instantiaions. There is no need to mix.
There is no any mix at this approach:
Base has only vector<Item> providing m1 method
DerivedBase has only vector<DerivedItem> providing m1 and m2 methods.
However, without knowing real usage pattern - it is hard to guess what you need. Maybe for your case two standalone vectors would be enough:
vector<Item> x1;
vector<DerivedItem> x2;
and just define stand-alone functions for them.