C++ vector of custom template class as member - c++

I'm currently coding a program in c++ using a template class:
template<typename TYPE>
class TemplateClass {
private:
TYPE t;
};
I have another class which acts as manager of my TemplateClass which should store multiple instances of this class in a vector. Different instances should have different types e.g. int, std::string, etc.. Speaking in Java ways the solution would be to just use something like in the example below but it seems like this is not possible in C++.
class ManagerClass {
private:
// Here seems to be the problem.
std::vector<TemplateClass<?>> templates;
}
Is it possible to do something like that?
Thank you for all answers

If you know all the types that will be stored in the std::vector at compile time I'd use an std::variant in such a case.
// This is used for the visitor pattern.
template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
// The below line not needed in C++20...
template<class... Ts> overload(Ts...) -> overload<Ts...>;
template<typename T>
struct MyClass { T value; };
using types = std::variant<
MyClass<std::string>,
MyClass<int>,
MyClass<double>>;
int main()
{
std::vector<types> stuff{};
stuff.push_back(MyClass<std::string>{});
stuff.push_back(MyClass<int>{});
stuff.push_back(MyClass<double>{});
for(const auto& v : stuff)
{
if (std::holds_alternative<MyClass<std::string>>(v))
{
std::cout << "Im a string\n";
}
else if (auto* p{std::get_if<MyClass<int>>(&v)})
{
std::cout << "Im an int\n";
}
else
{
auto t = std::get<MyClass<double>>(v);
std::cout << "Im a double\n";
}
// Or you can use the visitor pattern.
std::visit(overload{
[](const MyClass<std::string>& ) { std::cout << "I'm a string\n"; },
[](const MyClass<int>& ) { std::cout << "I'm a int\n"; },
[](const MyClass<double>& ) { std::cout << "I'm a double\n"; },
}, v);
}
}

If you can use C++17, you can use std::any or std::variant.
class ManagerClass {
private:
using variant_type = std::variant<
TemplateClass<std::string>,
TemplateClass<int>,
TemplateClass<double> >;
std::vector<variant_type> templates;
};

This is one way of doing it via runtime polymorphishm, which is achieved by function overriding. Function overriding occurs when a derived class has a definition for one of the member functions of the base class. That base function is said to be overridden.
#include <iostream>
#include <vector>
using namespace std;
// Base class declaration
class Base {
public:
virtual void print()
{
cout << "Base" << endl;
}
virtual ~Base(){}
};
// Derived Class 1
class Derived1 : public Base {
public:
void print()
{
cout << "Derived1" << endl;
}
};
// Derived class 2
class Derived2 : public Base {
public:
void print()
{
cout << "Derived2" << endl;
}
};
int main()
{
Base* d1 = new Derived1();
Base* d2 = new Derived2();
vector<Base*> myVec;
myVec.push_back(d1);
myVec.push_back(d2);
for (auto i : myVec) {
i->print();
}
delete d1;
delete d2;
return 0;
}

Related

How to make two classes with different member variable type and different constructor into derived/base class or template class?

class Data
{
public:
int i;
};
auto cmp = [](const Data& d1, const Data& d2) { return d1.i > d2.i; };
class A
{
private:
queue<Data> q;
public:
A() {};
void func() {
int cnt = 0;
while (!q.empty()) {
std::cout << cnt++ << std::endl;
q.pop();
}
}
};
class B
{
private:
priority_queue<Data, vector<Data>, decltype(cmp)> q;
public:
B() :q(cmp) {};
void func() {
int cnt = 0;
while (!q.empty()) {
std::cout << cnt++ << std::endl;
q.pop();
}
}
};
I define two classes A and B.As seen, their member func is the same, but with different member variable type q and different constructor.
So could I make A and B into two class derived from one base class (but with func in base class) or make them into a template class?(That is to say, I only want to write func once..)
If could, then how?
In both cases, it looks like you are just trying to count the number of items in a collection class before erasing it. If that's the case, let's just keep it simple.
void func() {
queue<Data> empty_queue;
cout << "About to erase a queue of size " << q.size() << "\n";
q.swap(empty_queue);
}
OR
void func() {
priority_queue<Data, vector<Data>, decltype(cmp)> empty_queue;
cout << "About to erase a queue of size " << q.size() << "\n";
q.swap(empty_queue);
}
I was about to recommend an inheritance strategy where A and B derived from a Base template class. But after I coded it, I didn't like the idea of deriving from what's ostensibly a queue class. You can't honestly say that A or B are "is a" of a queue. But here's what I wrote and I don't like it.
template <typename T>
class Base
{
protected:
T q;
public:
void func()
{
T empty_queue;
q.swap(empty_queue);
}
};
class A : public Base<queue<Data>>
{
public:
A() {};
};
class B : public Base<priority_queue<Data, vector<Data>, decltype(cmp)>>
{
public:
B() {}
};
A better approach might to just write a single template function:
template <typename T>
void EraseCollectionClass(T& t) {
T empty;
t.swap(empty);
}
And then keep your original implementations:
class A
{
private:
queue<Data> q;
public:
A() {};
void func() {
EraseCollectionClass(q);
}
};
class B
{
private:
priority_queue<Data, vector<Data>, decltype(cmp)> q;
public:
B() :q(cmp) {};
void func() {
EraseCollectionClass(q);
}
};

using intermediate class in a Crtp hierarchy without declaring a new class

I have a hierarchy similar to the following:
#include <iostream>
template<typename DerivedCrtp>
struct A
{
void Print() { std::cout << "A";}
};
struct B : public A<B>
{
};
template<typename DerivedCrtp>
struct C : public A<C<DerivedCrtp>>
{
void Print() { std::cout << "C";}
};
template<typename DerivedCrtp>
struct D : public C<D<DerivedCrtp>>
{
void Print() { std::cout << "D";}
};
struct CFinalized : public C<CFinalized>
{
void Print() { std::cout << "CFinal";}
};
template<typename DerivedCrtp = CSmart<>>
struct CSmart : public A<C<DerivedCrtp>>
{
void Print() { std::cout << "C";}
};
int main()
{
C<int> c;
D<int> d;
CFinalized cf;
c.Print();
d.Print();
cf.Print();
}
Because C is using crtp I can't directly use it without providing the self derived type DerivedCrtp.
In order to use it I need to "finalize" it's type (see CFinalized).
It works but every time I need to use a class part of that hierarchy (that in my real code is deeper and contains several more template parameters), I need to explicitly declare a new class.
Is there a smarter way to do this?

Injecting a function into a subclass

Is it possible to do such things in C++14. I have a base class as follows:
#include <iostream>
class AbstractElement;
class ConcreteElement;
class SuperConcreteElement;
class B
{
public:
void bar(AbstractElement*)
{
std::cout << "Abstract element" << std::endl;
}
void bar(ConcreteElement*)
{
std::cout << "Concrete element" << std::endl;
}
void bar(SuperConcreteElement*)
{
std::cout << "Super concrete element" << std::endl;
}
};
class AbstractElement
{
public:
virtual void foo() = 0;
};
class ConcreteElement : public AbstractElement
{
private:
B _b;
public:
void foo()
{
_b.bar(this); //1
}
};
class SuperConcreteElement : public AbstractElement
{
private:
B _b;
public:
void foo()
{
_b.bar(this); //2
}
};
int main()
{
AbstractElement *e = new ConcreteElement();
e -> foo(); //Prints Concrete element
}
As you can see at //1 and //2, the function's body is completely similar. But I can't quite move it into a base class because of depending on the static type of this. In spite of that fact, I wouldn't like to write absolutely the same code every time I need to add one more subclass of AbstractElement. So, I need some kind of mechanism which provides us with the facility to inject code into a function.
As long as marcos are not very desirable solution, I'd like to ask about some tricks that can be done in C++14 for solving such a problem.
Yes, it is possible using CRTP:
#include <iostream>
class AbstractElement;
class ConcreteElement;
class SuperConcreteElement;
class B
{
public:
void bar(AbstractElement*)
{
std::cout << "Abstract element" << std::endl;
}
void bar(ConcreteElement*)
{
std::cout << "Concrete element" << std::endl;
}
void bar(SuperConcreteElement*)
{
std::cout << "Super concrete element" << std::endl;
}
};
class AbstractElement
{
public:
virtual void foo() = 0;
};
template <class T>
class CRTPAbstractElement : public AbstractElement
{
B _b;
public:
virtual void foo()
{
T* t = dynamic_cast<T *>(this);
_b.bar(t);
}
};
class ConcreteElement : public CRTPAbstractElement<ConcreteElement>
{
};
class SuperConcreteElement : public CRTPAbstractElement<SuperConcreteElement>
{
};
int main()
{
AbstractElement *e = new ConcreteElement();
e -> foo(); //Prints Concrete element
}
By adding an intermediate CRTP class we are able to cast a pointer to the base class to a pointer to the derived class. Thus solving the issue of code duplication.

Implement the "visitor pattern" with templates

I'm trying to implement a modified version of the visitor pattern in a parametric manner, avoiding in this way a "universal visitor" with a overload for each concrete element, but, due to I haven't a lot of experience in template programming I don't know how I can complete the "pattern".
Code:
// test.cpp
#include <iostream>
#include <vector>
using namespace std;
struct Base
{
virtual ~Base() {}
virtual void visit() = 0;
};
template<typename Visitor>
struct ElementBase : public Base
{
// No virtual.
void visit()
{
_e.visit(this);
}
private:
Visitor _e;
};
// Atoms.
template<typename Visitor>
struct ElementA : public ElementBase<Visitor>
{
ElementA() : a(5) {}
int a;
};
// Visitors.
struct VisitorA
{
void visit(ElementBase<VisitorA> *a)
{
ElementA<VisitorA>* elto = dynamic_cast<ElementA<VisitorA>*>(a);
cout << elto->a << endl;
}
/*
void visit(ElementA<VisitorA> *a)
{
cout << a->a << endl;
}
*/
};
std::vector<Base*> v;
int main()
{
v.push_back(new ElementA<VisitorA>());
for (auto i : v)
i->visit();
}
This works fine and its output is 5 (as expected). But that I pretend is to make the same but directly with the second (commented) version of the "visit" in VisitorA.
Obviously, this doesn't work because "this" has the type ElementBase<...>*.
How can I downcast the pointer "this" to the actual derived class inside ElementBase?
Like user786653 says, the Curiously Recurring Template Pattern can solve this
template<typename Visitor, typename Derived>
struct ElementBase : public Base
{
void visit()
{
_e.visit(static_cast<Derived*>(this));
}
private:
Visitor _e;
};
// Atoms.
template<typename Visitor>
struct ElementA : public ElementBase<Visitor, ElementA<Visitor> >
{
ElementA() : a(5) {}
int a;
};
// Visitors.
struct VisitorA
{
void visit(ElementA<VisitorA> *a)
{
cout << a->a << endl;
}
};

How to treat Base* pointer as Derived<T>* pointer?

I would like to store pointers to a Base class in a vector, but then use them as function arguments where they act as a specific class, see here:
#include <iostream>
#include <vector>
class Base {};
template<class T>
class Derived : public Base {};
void Foo(Derived<int>* d) {
std::cerr << "Processing int" << std::endl;
}
void Foo(Derived<double>* d) {
std::cerr << "Processing double" << std::endl;
}
int main() {
std::vector<Base*> vec;
vec.push_back(new Derived<int>());
vec.push_back(new Derived<double>());
Foo(vec[0]);
Foo(vec[1]);
delete vec[0];
delete vec[1];
return 0;
}
This doesn't compile:
error: call of overloaded 'Foo(Base*&)' is ambiguous
Is it possible to make it work? I need to process the elements of the vector differently, according to their int, double, etc. types.
You'll need to use method polymorphism, as it's dynamic, rather than function overloading, which is static (compile-time). To overload on a templated type, you'll need to use template specialization.
Example:
#include <iostream>
#include <vector>
class Base {
public:
virtual void Foo() {
std::cerr << "Processing base" << std::endl;
}
};
template<class T>
class Derived : public Base {};
template <>
class Derived <int> : public Base {
public:
void Foo() {
std::cerr << "Processing int" << std::endl;
}
};
template <>
class Derived <double> : public Base {
public:
void Foo() {
std::cerr << "Processing double" << std::endl;
}
};
int main() {
std::vector<Base*> vec;
vec.push_back(new Derived<int>());
vec.push_back(new Derived<double>());
vec[0]->Foo();
vec[1]->Foo();
delete vec[0];
delete vec[1];
return 0;
}
When you typecast from Derived<int>* to Base*, you lose the information about what derived class you have, unless you use RTTI (RunTime Type Identification).
If you have enabled RTTI, then you can try to typecast a Base* forward to a derived type pointer by using dynamic_cast<>():
void Foo(Base* base)
{
Derived<int>* derivedInt = dynamic_cast<Derived<int>*>(base);
if(derivedInt)
{
Foo(derivedInt);
return;
}
Derived<double>* derivedDouble = dynamic_cast<Derived<double>*>(base);
if(derivedDouble)
{
Foo(derivedDouble);
return;
}
// Handle other cases here.
}
dynamic_cast returns NULL if the pointer doesn't point to the correct type.
Alternatively, if you don't want to use RTTI and dynamic_cast, you have to maintain some means for determining which subclass is stored in your vector (usually an enum value stored along with the pointer, maybe in a pair, or with a method in Base that returns a similar enum) and use reinterpret_cast<>() to typecast the pointer.
Of course it is ambiguous, how can the compiler figure out which specific subclass of Base is held in vec[0].
You can resolve the ambiguity by an explicit cast:
Foo( (Derived<int>*) vec[0] )
or, better, consider using dynamic method resolution:
class Base {
virtual void Foo() = 0;
};
template <class T>
class Derived: Base {
void Foo() { /* .. doFoo<T>(...) .. */ }
};
template<class T> void doFoo() { /* .. general case .. */ }
template<> void doFoo<int>() { /* .. int case .. */}
template<> void doFoo<double>() { /* .. double case .. */}
and in your code just call
vec[0]->Foo()
You can do it like this:
#include <iostream>
#include <vector>
class Base {
public:
virtual void DoFoo() = 0;
};
template<class T>
class Derived : public Base {
public:
virtual void DoFoo() {
Foo(this);
}
};
void Foo(Derived<int>* d) {
std::cerr << "Processing int" << std::endl;
}
void Foo(Derived<double>* d) {
std::cerr << "Processing double" << std::endl;
}
int main()
{
std::vector<Base*> vec;
vec.push_back(new Derived<int>());
vec.push_back(new Derived<double>());
vec[0]->DoFoo();
vec[1]->DoFoo();
delete vec[0];
delete vec[1];
return 0;
}