Policy-based template design: How to access certain policies of the class? - c++

I have a class that uses several policies that are templated. It is called Dish in the following example. I store many of these Dishes in a vector (using a pointer to simple base class), but then I'd like to extract and use them. But I don't know their exact types.
Here is the code; it's a bit long, but really simple:
#include <iostream>
#include <vector>
struct DishBase {
int id;
DishBase(int i) : id(i) {}
};
std::ostream& operator<<(std::ostream& out, const DishBase& d) {
out << d.id;
return out;
}
// Policy-based class:
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase {
Appetizer appetizer_;
Main main_;
Dessert dessert_;
public:
Dish(int id) : DishBase(id) {}
const Appetizer& get_appetizer() { return appetizer_; }
const Main& get_main() { return main_; }
const Dessert& get_dessert() { return dessert_; }
};
struct Storage {
typedef DishBase* value_type;
typedef std::vector<value_type> Container;
typedef Container::const_iterator const_iterator;
Container container;
Storage() {
container.push_back(new Dish<int,double,float>(0));
container.push_back(new Dish<double,int,double>(1));
container.push_back(new Dish<int,int,int>(2));
}
~Storage() {
// delete objects
}
const_iterator begin() { return container.begin(); }
const_iterator end() { return container.end(); }
};
int main() {
Storage s;
for(Storage::const_iterator it = s.begin(); it != s.end(); ++it){
std::cout << **it << std::endl;
std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
}
return 0;
}
The tricky part is here, in the main() function:
std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
How can I access the dessert? I don't even know the Dessert type (it is templated), let alone the complete type of the object that I'm getting from the storage.
This is just a toy example, but I think my code reduces to this. I'd just like to pass those Dish classes around, and different parts of the code will access different parts of it (in the example: its appetizer, main dish, or dessert).

What you have is not exactly policy-based design IMO... if it were, your class should've actually implemented (i.e. extended) the policies.
Now, back to your question/example. In your container, you store a "DishBase*". Right? From that point on, you loose any compile-time information wrt the actual type of the objects in the collection. So, I'm afraid what you try to do is provably impossible.
What you could do, is use an actual policy-based design, eg.
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase, Appetizer, Main, Dessert {
}
Then, you could simply use dynamic_cast to check at runtime that you can convert your object to any concrete Appetizer/Dessert/Main.
But from your description, I get the impression that you actually need abstract base classes (i.e. abstract base classes may be the design that makes sense for you, and not policies).

You will need to have appropriate member functions for querying (in this case an overload for the concrete Dessert type). The policies should expose a way of discovery. Here's a short example:
#include <iostream>
using namespace std;
struct TA { virtual string foo() { return "TA::foo\n"; } };
struct DTA : TA { virtual string foo() { return "DTA::foo\n"; } };
template <class T>
struct C {
T t;
};
template <class T>
ostream& operator <<(ostream& o, C<T> c) {
o << c.t.foo();
return o;
}
int main(int argc, char* argv[])
{
C<DTA> c;
cout << c;
}

My understanding is that policy-based template classes are not very container friendly. I just opt for plain old polymorphism for this kind of things. I'd be interested in a solution though.
EDIT: It's perhaps not by coincidence that I cannot find any usage of stl containers throughout Alexandrescu's "Modern C++ Desing" book.
EDIT2: More details on the friction between polymorphism and genericity can be found here http://www.artima.com/cppsource/type_erasure.html. You container can perhaps be made of boost::any objects?

Related

How to return a variant from an input iterator with high performance?

I have some file format decoder which returns a custom input iterator. The value type of this iterator (when dereferencing it with *iter) can be one of many token types.
Here's a simplified usage example:
File file {"/path/to/file"};
for (const auto& token : file) {
// do something with token
}
How can this token have multiple possible types? Depending on the type of the token, the type of its payload changes too.
Performance is important here during traversal. I don't want any unnecessary allocation, for example. This is why the iterator's type is an input iterator: as soon as you advance the iterator, the previous token is invalidated as per the requirements of the InputIterator tag.
I have two ideas in mind so far:
Use a single Token class with a private union of all the possible payloads (with their public getters) and a public type ID (enum) getter.
The user needs to switch on this type ID to know which payload getter to call:
for (const auto& token : file) {
switch (token.type()) {
case Token::Type::APPLE:
const auto& apple = token.apple();
// ...
break;
case Token::Type::BANANA:
const auto& banana = token.banana();
// ...
break;
// ...
}
}
Although this is probably what I would choose in C, I'm not a fan of this solution in C++ because the user can still call the wrong getter and nothing can enforce this (except run-time checks which I want to avoid for performance concerns).
Create an abstract Token base class which has an accept() method to accept a visitor, and multiple concrete classes (one for each payload type) inheriting this base class. In the iterator object, instantiate one of each concrete class at creation time. Also have a Token *token member. When iterating, fill the appropriate pre-allocated payload object, and set this->token = this->specificToken. Make operator*() return this->token (reference to). Ask the user to use a visitor during the iteration (or worse, use dynamic_cast):
class MyVisitor : public TokenVisitor {
public:
void visit(const AppleToken& token) override {
// ...
}
void visit(const BananaToken& token) override {
// ...
}
};
TokenVisitor visitor;
for (const auto& token : file) {
token.accept(visitor);
}
This introduces additional function calls for each token, at least one of them which is virtual, but this might not be the end of the world; I remain open to this solution.
Is there any other interesting solution? I consider that returning a boost::variant or std::variant is the same as idea #2.
Although this is probably what I would choose in C, I'm not a fan of this solution in C++ because the user can still call the wrong getter and nothing can enforce this (except run-time checks which I want to avoid for performance concerns).
You can reverse the approach and accept a callable object instead of returning an iterator to the user. Then you can iterate the container internally and dispatch the right type. This way users cannot do mistakes anymore by ignoring the information carried up with your tagged union, for you are in charge of taking it in consideration.
Here is a minimal, working example to show what I mean:
#include <vector>
#include <utility>
#include <iostream>
struct A {};
struct B {};
class C {
struct S {
enum { A_TAG, B_TAG } tag;
union { A a; B b; };
};
public:
void add(A a) {
S s;
s.a = a;
s.tag = S::A_TAG;
vec.push_back(s);
}
void add(B b) {
S s;
s.b = b;
s.tag = S::B_TAG;
vec.push_back(s);
}
template<typename F>
void iterate(F &&f) {
for(auto &&s: vec) {
if(s.tag == S::A_TAG) {
std::forward<F>(f)(s.a);
} else {
std::forward<F>(f)(s.b);
}
}
}
private:
std::vector<S> vec;
};
void f(const A &) {
std::cout << "A" << std::endl;
}
void f(const B &) {
std::cout << "B" << std::endl;
}
int main() {
C c;
c.add(A{});
c.add(B{});
c.add(A{});
c.iterate([](auto item) { f(item); });
}
See it up and running on Coliru.

Iterator Class Design in C++

I am trying to learn the concept of writing a generic iterator in C++. I came across this example given below. I don't understand the use of having NameCollection::value_type here. Why can't we have
Iterator<value_type> since its a templated class.
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
class Iterator {
public:
typedef T value_type;
virtual bool hasNext() = 0;
virtual T next() = 0;
};
class NameManager {
typedef vector<string> NameCollection;
NameCollection m_names;
public:
class NameIterator: public Iterator< NameCollection::value_type > {
friend class NameManager;
private:
NameManager::NameCollection & m_names;
NameManager::NameCollection::iterator m_itr;
NameIterator(NameManager::NameCollection & names) : m_names(names), m_itr(m_names.begin()) {}
public:
virtual bool hasNext() {
return m_itr!=m_names.end();
}
virtual NameIterator::value_type next(void) {
NameIterator::value_type value = (*m_itr);
++m_itr;
return value;
}
};
void addName(NameCollection::value_type name){
m_names.push_back(name);
}
NameIterator getNameIterator(void) {
return NameIterator(m_names);
}
};
int main(void) {
NameManager nameMgr;
nameMgr.addName("Jobs");
nameMgr.addName("Bill");
nameMgr.addName("Larry");
NameManager::NameIterator nameItr = nameMgr.getNameIterator();
while(nameItr.hasNext()) {
cout<<nameItr.next() << endl;
}
return 0;
}
Imagine you are writing generic code which should be able to work with any (or at least generic) iterators. Think about something from the <algorithm>. Such a code might be interested in the type of value (type of the expression *it). So value_type typedef is a standard interface to pass around this information.
NameCollection::value_type is std::string, of course. It can serve the same purpose: assume you want to change your underplaying container to use wide strings, or something else. Now if you use std::string explicitely, you will have to find and replace it everywhere. If you use NameCollection::value_type only one line has to be changed.
You can use it in the function 'next' as well (it will work), but semantically it makes much more sense to use iterator there, since this function is all about iterators.

Generic design mixed with curiously recurring template pattern. C++

Consider this kind of problem. I have a Base class and three classes derived from Base. For instance: DerivedA, DerivedB and DerivedC. Each derived class has its unique container. Hence DerivedA has std::vector<int>, DerivedB has std::set<int> and DerivedC has std::map<int, std::string>. And I want an interface in Base to access the container of derived class on which it is currently pointed to.
Base* d1 = new DerivedA;
for(std::vector<int>::iterator iter = d1->begin(); iter != d1->end(); ++iter)
{
//processing
}
I tried to wrap each container to separate class and keep a pointer of their base
in the Base class.
class CollA;
template<class T>
class traits;
template<>
class traits<CollA>
{
public:
typedef vector<int> container;
};
template<class T>
class Coll
{
public:
typedef typename traits<T>::container container;
typename container::iterator begin() const
{
}
};
class CollA : public Coll<CollA>
{
typedef traits<CollA>::container container;
public:
container::iterator begin()
{
return V.begin();
}
private:
vector<int> V;
};
class Base
{
public:
Base()
{
}
// what to do here? I must keep a pointer to Coll; But Coll itself is a template
};
Suggest me something. I am kind of lost in this horrible design.
In order to do what you want, you need to define a common type of iterator that can be returned from the different begin() and end() overrides in the derived classes.
Before that, of course, you need to decide what exactly you want that iterator to do, as Yakk explained in his comment. For starters, you need to decide what value_type will result from indirecting through such an iterator. The only common type that I can think of given your three different containers is const int, as keys in std::maps are const and std::set iterators are const iterators (since the elements are keys themselves). So, when iterating using the common iterator type, you'll only be able to observe the ints in there.
Now, the iterator implementation will need to call different code (at runtime) depending on the derived class from which it originated. This is a typical use case for type erasure. When done properly, this would allow you to wrap any kind of iterator, as long as it supports the interface you need. In your case however, you may not need to go that far, since I suppose you know the full set of containers you need to support, so the set of iterator types is well known and bounded as well.
This means you can use a boost::variant to store the wrapped iterator. This should be more efficient than a full type erasure solution, since it avoids some internal virtual function calls and possibly some heap allocations (unless the type erasure solution can use some kind of small object optimization, which is fairly possible for iterators, but is even more complicated to implement).
Here's a skeleton implementation of such an iterator, together with the class hierarchy using it and some simple test code. Note that I've only implemented the basic iterator functionality that's needed to make your loop work.
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iterator>
#include "boost/variant.hpp"
//Helper function object types to implement each operator on the variant iterator.
struct indirection_visitor : boost::static_visitor<const int&>
{
const int& operator()(std::vector<int>::iterator i) const { return *i; }
const int& operator()(std::set<int>::iterator i) const { return *i; }
const int& operator()(std::map<int, std::string>::iterator i) const { return i->first; }
};
struct prefix_increment_visitor : boost::static_visitor<>
{
template<typename I> void operator()(I& i) const { ++i; }
};
//The iterator itself.
//It should probably hide the internal variant, in which case the non-member operators
//should be declared as friends.
struct var_iterator : std::iterator<std::bidirectional_iterator_tag, const int>
{
var_iterator() { }
template<typename I> var_iterator(I i) : it(i) { }
boost::variant<std::vector<int>::iterator, std::set<int>::iterator, std::map<int, std::string>::iterator> it;
const int& operator*() { return boost::apply_visitor(indirection_visitor(), it); }
var_iterator& operator++()
{
boost::apply_visitor(prefix_increment_visitor(), it);
return *this;
}
};
inline bool operator==(var_iterator i1, var_iterator i2) { return i1.it == i2.it; }
inline bool operator!=(var_iterator i1, var_iterator i2) { return !(i1 == i2); }
//Here's the class hierarchy.
//We use CRTP only to avoid copying and pasting the begin() and end() overrides for each derived class.
struct Base
{
virtual var_iterator begin() = 0;
virtual var_iterator end() = 0;
};
template<typename D> struct Base_container : Base
{
var_iterator begin() override { return static_cast<D*>(this)->container.begin(); }
var_iterator end() override { return static_cast<D*>(this)->container.end(); }
};
struct DerivedA : Base_container<DerivedA>
{
std::vector<int> container;
};
struct DerivedB : Base_container<DerivedB>
{
std::set<int> container;
};
struct DerivedC : Base_container<DerivedC>
{
std::map<int, std::string> container;
};
//Quick test.
void f(Base* bp)
{
for(auto iter = bp->begin(); iter != bp->end(); ++iter)
{
std::cout << *iter << ' ';
}
std::cout << '\n';
//We have enough to make range-based for work too.
for(auto i : *bp)
std::cout << i << ' ';
std::cout << '\n';
}
int main()
{
DerivedA da;
da.container = {1, 2, 3};
f(&da);
DerivedB db;
db.container = {4, 5, 6};
f(&db);
DerivedC dc;
dc.container = std::map<int, std::string>{{7, "seven"}, {8, "eight"}, {9, "nine"}};
f(&dc);
}
Implementation notes:
As mentioned above, this is not a complete bidirectional iterator; I chose that tag as the most powerful common iterator among your container types.
I compiled and (superficially) tested the code in Clang 3.6.0 and GCC 5.1.0 in C++11 mode, and in Visual C++ 2013, using boost 1.58.0.
The code works in C++14 mode as well in the compilers above (and also in Visual C++ 2015 CTP6), but needs a small change because of a bug in boost 1.58 (I'll have to report that), otherwise you'll get an ambiguity error. You need to remove the base class of indirection_visitor and let the return type of this visitor be determined automatically. This only works in C++14, as it uses decltype(auto) internally, and it's this new code that causes the ambiguity. Earlier versions of boost don't have this problem, but don't have autodetection of return types either.
In C++14 mode and boost 1.58, you can use generic lambdas to implement simple visitors like prefix_increment_visitor, which makes the code more straightforward.
I removed the comparison visitors from my first version of the code, as boost::variant already provides a default equality operator and it's enough for this case (the example is long enough as it is).
You can add const in the required places to get true const iterator behaviour if needed (qualify begin() and end(), use static_cast<const D*> in CRTP, declare the variant to contain const_iterators, adjust the visitor).
You can, of course, implement some sort of poor-man's variant and avoid using boost, but boost::variant makes everything much easier, cleaner and safer.

How to pass a class (not an object) as a parameter in C++

Introdutory note: I started studying C++ in college about a month ago. This is for an assignment. We are staring out now and do not grasp many advanced concepts.
tl;dr: let's imagine you have a Book. The Book is a dynamic array of Pages*. Each Page can be a WrittenPage or a DrawnPage. If you want to print all the Pages you use a virtual method. If you just want to print the DrawnPages or WrittenPages you'll have to do some sort of filtering inside the Book. How to do that? For now I discovered you'll need typeid or some sort of other mean to compare the subtype of each Page. If you're in a hurry for something quick and simple take a look at the accepted answer, by #CantChooseUsernames. It's working well for my problem. If you have some more expertise I'd like to hear what you think about the new answer by #n.m. . Don't let the currently accepted answer discourage you from commenting or posting your own if you think it brings something new and meaningful to the discussion.
ORIGINAL QUESTION:
I have a class MyObj that's a superclass of TheseObj and ThoseObj.
Class TheseObj : public MyObj {
}
Class ThoseObj : public MyObj {
}
I have another class that contains an std::vector with pointers to MyObj instances and a non-static method in which I want to list only TheseObj:
Class MyClass {
private:
vector<MyObj*> vec;
public:
void listTheseObj() {
for each (myObj* obj in vec) {
if(typeid(*obj) == typeid(theseObj)) {
cout << *obj << endl;
}
}
}
}
All operators are already correctly overloaded.
This works great. Now the problem is that I have a lot more places where I need to do the same, so I'm in need of a template method that could receive a GENERIC vector and a class TYPE, in order for me to do something like:
listObjects(class_name_here, vec);
I managed to create:
template <class T>
void listObjectsOfOneType(const type_info& class_name_here, const vector<T*>& vec) {
for each (T* obj in vec) {
if(typeid(*obj) == typeid(class_name_here)) {
cout << *obj << endl;
}
}
}
But I'm not sure:
If the template method is right
How can I call it
Hope I've made myself clear, thank you very much in advance for your time.
I would probably avoid using TypeID.. Though, I'm not sure exactly what you want to achieve but this is what I believe you are asking for:
#include <iostream>
#include <vector>
#include <typeinfo>
template <class T, class U>
void ListObjects(std::vector<U*> &vec)
{
for (U* obj : vec)
{
if (typeid(*obj) == typeid(T))
{
obj->Print();
std::cout<<"\n";
}
}
}
class Parent
{
public:
Parent() {std::cout<<"Parent Constructed\n";}
virtual ~Parent() {std::cout<<"Parent Destructed\n";}
virtual void Print(){std::cout<<"Parent\n";}
};
class Brother : public Parent
{
public:
Brother(){std::cout<<"Brother Constructed\n";}
virtual ~Brother(){std::cout<<"Brother Destructed\n";}
void Print() override {std::cout<<"Brother\n";}
};
class Sister : public Parent
{
public:
Sister(){std::cout<<"Sister Constructed\n";}
virtual ~Sister(){std::cout<<"Sister Destructed\n";}
void Print() override {std::cout<<"Sister\n";}
};
int main()
{
std::vector<Parent*> Objects;
Objects.push_back(new Parent());
Objects.push_back(new Brother());
Objects.push_back(new Sister());
std::cout<<"\n";
ListObjects<Parent>(Objects);
ListObjects<Brother>(Objects);
ListObjects<Sister>(Objects);
for (Parent* c : Objects)
{
delete c;
}
}
Which prints:
Parent Constructed
Parent Constructed
Brother Constructed
Parent Constructed
Sister Constructed
Parent
Brother
Sister
Parent Destructed
Brother Destructed
Parent Destructed
Sister Destructed
Parent Destructed
Process returned 0 (0x0) execution time : 0.066 s
Press any key to continue.
A lot of comments are telling you to use not use TypeID because we are NOT sure what you want.. However, what we mean by "there is no need for typeid" assuming that we know what you want, then the following would be valid:
#include <iostream>
#include <vector>
#include <typeinfo>
template <class T>
void ListObjects(std::vector<T*> &vec)
{
for (T* obj : vec)
{
//TypeID isn't needed here because the virtual call will figure out which class's << operator to call.
//If each class has a print function, it can also figure out which class's print function to call..
//obj->Print(); //works too because each class has a print func.
std::cout<<*obj<<"\n"; //Works because each class has an overloaded << operator.
}
}
class Parent
{
protected:
virtual void Print(std::ostream& os) const {os<<"Parent\n";}
public:
Parent() {std::cout<<"Parent Constructed\n";}
virtual ~Parent() {std::cout<<"Parent Destructed\n";}
friend std::ostream& operator << (std::ostream &os, const Parent &p);
};
std::ostream& operator << (std::ostream &os, const Parent &p)
{
p.Print(os);
return os;
}
class Brother : public Parent
{
protected:
void Print(std::ostream& os) const override {os<<"Brother\n";}
public:
Brother(){std::cout<<"Brother Constructed\n";}
virtual ~Brother() {std::cout<<"Brother Destructed\n";}
};
class Sister : public Parent
{
protected:
void Print(std::ostream& os) const override {os<<"Sister\n";}
public:
Sister(){std::cout<<"Sister Constructed\n";}
virtual ~Sister(){std::cout<<"Sister Destructed\n";}
};
int main()
{
std::vector<Parent*> Objects;
Objects.push_back(new Parent());
Objects.push_back(new Brother());
Objects.push_back(new Sister());
std::cout<<"\n";
ListObjects(Objects); //NOTICE we all template types are now inferred.
for (Parent* c : Objects)
{
delete c;
}
}
Notice in the above that since the call is virtual, the code prints the same as the code that uses TypeID and the code no longer needs you to type anything in the template's braces. It is inferred because we no longer need to compare using typeid.
Now since you requested the previous code with the template being a parameter instead, then:
template <class T, class U>
void ListObjects(std::vector<U*> &vec)
{
for (U* obj : vec)
{
if (typeid(*obj) == typeid(T))
{
obj->Print();
std::cout<<"\n";
}
}
}
would become:
template<typename T>
void ListObjects(std::vector<T*> &vec, const std::type_info &type)
{
for (T* obj : vec)
{
if (typeid(*obj) == type)
{
std::cout<<*obj<<"\n";
}
}
}
and you'd use it like: ListObjects(Objects, typeid(Child));
Again, all of these give you the exact same result. It all depends on your needs/use-case. We don't exactly know "what" you want to achieve. These should help you out though.
Unless you are doing this as part of a test just to figure out what is going on somewhere in your code, I agree with commenters that this is a very bad idea.
template < typename T >
void listObjects(const std::vector<MyObj*>& vec) {
for (MyObj* obj: vec) {
if (typeid(*obj) == typeid(T)) {
// one of the two below, depending on what your op<< looks like
std::cout << *obj << std::endl;
std::cout << dynamic_cast<T&>(*obj) << std::endl;
}
}
}
void calledLikeThis(const std::vector<MyObj*>& vec) {
listObjects<TheseObj>(vec);
}
Using typeid in this manner violates Liskov Substitution principle. LSP, roughly speaking, says that if your function works with objects of class X, it should also work with (some) objects of any subclass of X. Your listTheseObj function will only list objects which are exactly of type TheseObj, but not of any subtype.
That's OK for debugging purposes, or for infrastructure/framework projects, where you implement services like reflection or serialization and index them with typeid(obj). But business logic should not work like that. Users are not interested in whatever technical reason makes you split TheseObj into several subtypes; they want their notion of type (if at all).
If you want to print only TheseObj and any subclass-type object, you can replace
typeid(*obj) == typeid(TheseObj)
with
dynamic_cast<TheseObj*>(obj) != 0
A templated version would look like this:
template<typename T, typename U>
void ListObjects(std::vector<T*> &vec>)
{
for (T* obj : vec)
{
if (dynamic_cast<U*>(obj) != 0)
{
std::cout<<*obj<<"\n";
}
}
}
It is worth noting that the body of the if doesn't use the condition in any way. This hints on a possibility to separate them.
template<typename T>
void ActOnObjects(std::vector<T*> &vec>, std::function<bool(T*)> predicate,
std::function<void(T*)> action)
{
for (T* obj : vec)
{
if (predicate(obj))
{
action(obj);
}
}
}
Now you can filter with any predicate, using RTTI or not.
ActOnObjects(objects, [](T* obj){return dynamic_cast<ThatObj*>(obj) != 0;},
[](T* obj){std::cout << *obj << std::endl;});
ActOnObjects(objects, [](T* obj){return obj->isVeryImportant();},
[](T* obj){std::cout << *obj << std::endl;});
ActOnObjects(objects, [](T* obj){return obj->isBlue() && obj->isWobbly();},
[](T* obj){std::cout << *obj << std::endl;});
Also please use iterator ranges instead of containers, like any good citizen of the C++-land; I leave this as an exercise.

C++ Push Multiple Types onto Vector

Note: I know similar questions to this have been asked on SO before, but I did not find them helpful or very clear.
Second note: For the scope of this project/assignment, I'm trying to avoid third party libraries, such as Boost.
I am trying to see if there is a way I can have a single vector hold multiple types, in each of its indices. For example, say I have the following code sample:
vector<something magical to hold various types> vec;
int x = 3;
string hi = "Hello World";
MyStruct s = {3, "Hi", 4.01};
vec.push_back(x);
vec.push_back(hi);
vec.push_back(s);
I've heard vector<void*> could work, but then it gets tricky with memory allocation and then there is always the possibility that certain portions in nearby memory could be unintentionally overridden if a value inserted into a certain index is larger than expected.
In my actual application, I know what possible types may be inserted into a vector, but these types do not all derive from the same super class, and there is no guarantee that all of these types will be pushed onto the vector or in what order.
Is there a way that I can safely accomplish the objective I demonstrated in my code sample?
Thank you for your time.
The objects hold by the std::vector<T> need to be of a homogenous type. If you need to put objects of different type into one vector you need somehow erase their type and make them all look similar. You could use the moral equivalent of boost::any or boost::variant<...>. The idea of boost::any is to encapsulate a type hierarchy, storing a pointer to the base but pointing to a templatized derived. A very rough and incomplete outline looks something like this:
#include <algorithm>
#include <iostream>
class any
{
private:
struct base {
virtual ~base() {}
virtual base* clone() const = 0;
};
template <typename T>
struct data: base {
data(T const& value): value_(value) {}
base* clone() const { return new data<T>(*this); }
T value_;
};
base* ptr_;
public:
template <typename T> any(T const& value): ptr_(new data<T>(value)) {}
any(any const& other): ptr_(other.ptr_->clone()) {}
any& operator= (any const& other) {
any(other).swap(*this);
return *this;
}
~any() { delete this->ptr_; }
void swap(any& other) { std::swap(this->ptr_, other.ptr_); }
template <typename T>
T& get() {
return dynamic_cast<data<T>&>(*this->ptr_).value_;
}
};
int main()
{
any a0(17);
any a1(3.14);
try { a0.get<double>(); } catch (...) {}
a0 = a1;
std::cout << a0.get<double>() << "\n";
}
As suggested you can use various forms of unions, variants, etc. Depending on what you want to do with your stored objects, external polymorphism could do exactly what you want, if you can define all necessary operations in a base class interface.
Here's an example if all we want to do is print the objects to the console:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class any_type
{
public:
virtual ~any_type() {}
virtual void print() = 0;
};
template <class T>
class concrete_type : public any_type
{
public:
concrete_type(const T& value) : value_(value)
{}
virtual void print()
{
std::cout << value_ << '\n';
}
private:
T value_;
};
int main()
{
std::vector<std::unique_ptr<any_type>> v(2);
v[0].reset(new concrete_type<int>(99));
v[1].reset(new concrete_type<std::string>("Bottles of Beer"));
for(size_t x = 0; x < 2; ++x)
{
v[x]->print();
}
return 0;
}
In order to do that, you'll definitely need a wrapper class to somehow conceal the type information of your objects from the vector.
It's probably also good to have this class throw an exception when you try to get Type-A back when you have previously stored a Type-B into it.
Here is part of the Holder class from one of my projects. You can probably start from here.
Note: due to the use of unrestricted unions, this only works in C++11. More information about this can be found here: What are Unrestricted Unions proposed in C++11?
class Holder {
public:
enum Type {
BOOL,
INT,
STRING,
// Other types you want to store into vector.
};
template<typename T>
Holder (Type type, T val);
~Holder () {
// You want to properly destroy
// union members below that have non-trivial constructors
}
operator bool () const {
if (type_ != BOOL) {
throw SomeException();
}
return impl_.bool_;
}
// Do the same for other operators
// Or maybe use templates?
private:
union Impl {
bool bool_;
int int_;
string string_;
Impl() { new(&string_) string; }
} impl_;
Type type_;
// Other stuff.
};