Compare boost::any contents - c++

I am using a container to hold a list of pointers to anything:
struct Example {
std::vector<boost::any> elements;
}
To insert elements in this container, I had written a couple of helper functions (members of the struct Example):
void add_any(boost::any& a) {
elements.push_back(a);
}
template<typename T>
void add_to_list(T& a) {
boost::any bany = &a;
add_any(bany);
}
Now, I would like to insert elements only when they are not present in this container. To do this, I thought that I would only need to call search over elements with an appropriate comparator function. However, I do not know how to compare the boost::any instances.
My question:
Knowing that my boost::any instances always contain a pointer to something; is it possible to compare two boost::any values?
update
I thank you for your answers. I have also managed to do this in a probably unsafe way: using boost::unsafe_any_cast to obtain a void** and comparing the underlying pointer.
For the moment, this is working fine. I would, however, appreciate your comments: maybe this is a big mistake!
#include <boost/any.hpp>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool any_compare(const boost::any& a1, const boost::any& a2) {
cout << "compare " << *boost::unsafe_any_cast<void*>(&a1)
<< " with: " << *boost::unsafe_any_cast<void*>(&a2);
return (*boost::unsafe_any_cast<void*>(&a1)) ==
(*boost::unsafe_any_cast<void*>(&a2));
}
struct A {};
class Example {
public:
Example() : elements(0),
m_1(3.14),
m_2(42),
m_3("hello"),
m_4() {};
virtual ~Example() {};
void test_insert() {
add_to_list(m_1);
add_to_list(m_2);
add_to_list(m_3);
add_to_list(m_4);
add_to_list(m_1); // should not insert
add_to_list(m_2); // should not insert
add_to_list(m_3); // should not insert
add_to_list(m_4); // should not insert
};
template <typename T>
void add_to_list(T& a) {
boost::any bany = &a;
add_any(bany);
}
private:
vector<boost::any> elements;
double m_1;
int m_2;
string m_3;
A m_4;
void add_any(const boost::any& a) {
cout << "Trying to insert " << (*boost::unsafe_any_cast<void*>(&a)) << endl;
vector<boost::any>::const_iterator it;
for (it = elements.begin();
it != elements.end();
++it) {
if ( any_compare(a,*it) ) {
cout << " : not inserting, already in list" << endl;
return;
}
cout << endl;
}
cout << "Inserting " << (*boost::unsafe_any_cast<void*>(&a)) << endl;
elements.push_back(a);
};
};
int main(int argc, char *argv[]) {
Example ex;
ex.test_insert();
unsigned char c;
ex.add_to_list(c);
ex.add_to_list(c); // should not insert
return 0;
}

You cannot directly provide it, but you can actually use any as the underlying type... though for pointers it's pointless (ah!)
struct any {
std::type_info const& _info;
void* _address;
};
And a templated constructor:
template <typename T>
any::any(T* t):
_info(typeid(*t)),
_address(dynamic_cast<void*>(t))
{
}
This is, basically, boost::any.
Now we need to "augment" it with our comparison mechanism.
In order to do so, we'll "capture" the implementation of std::less.
typedef bool (*Comparer)(void*,void*);
template <typename T>
bool compare(void* lhs, void* rhs) const {
return std::less<T>()(*reinterpret_cast<T*>(lhs), *reinterpret_cast<T*>(rhs));
}
template <typename T>
Comparer make_comparer(T*) { return compare<T>; }
And augment the constructor of any.
struct any {
std::type_info const& _info;
void* _address;
Comparer _comparer;
};
template <typename T>
any::any(T* t):
_info(typeid(*t)),
_address(dynamic_cast<void*>(t)),
_comparer(make_comparer(t))
{
}
Then, we provided a specialization of less (or operator<)
bool operator<(any const& lhs, any const& rhs) {
if (lhs._info.before(rhs._info)) { return true; }
if (rhs._info.before(lhs._info)) { return false; }
return (*lhs._comparer)(lhs._address, rhs._address);
}
Note: encapsulation, etc... are left as an exercise to the reader

The only easy way to do this I can think of involves hardcoding support for the types that you're storing in the any instances, undermining much of the usefulness of any...
bool equal(const boost::any& lhs, const boost::any& rhs)
{
if (lhs.type() != rhs.type())
return false;
if (lhs.type() == typeid(std::string))
return any_cast<std::string>(lhs) == any_cast<std::string>(rhs);
if (lhs.type() == typeid(int))
return any_cast<int>(lhs) == any_cast<int>(rhs);
// ...
throw std::runtime_error("comparison of any unimplemented for type");
}
With C++11's type_index you could use a std::map or std::unordered_map keyed on std::type_index(some_boost_any_object.type()) - similar to what Alexandre suggests in his comment below.

If you can change type in container, there is Boost.TypeErasure. It provides easy way to customize any. For example I'm using such typedef for similar purpose:
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/operators.hpp>
using Foo = boost::type_erasure::any<
boost::mpl::vector<
boost::type_erasure::copy_constructible<>,
boost::type_erasure::equality_comparable<>,
boost::type_erasure::typeid_<>,
boost::type_erasure::relaxed
>
>;
Foo behaves exactly the same as boost::any, except that it can be compared for equality and use boost::type_erasure::any_cast instead of boost::any_cast.

There is no need to create new class. Try to use xany https://sourceforge.net/projects/extendableany/?source=directory xany class allows to add new methods to any's existing functionality. By the way there is a example in documentation which does exactly what you want (creates comparable_any).

Maybe this algorithm come in handy >
http://signmotion.blogspot.com/2011/12/boostany.html
Compare two any-values by type and content. Attempt convert string to number for equals.

Related

List of template classes of different types

I'm trying to make a list of template classes of variable types. So the idea is to loop of a list of objects that all have a common function, e.g. getValue, but a different type. The type could be any type, raw types or objects.
I need this because i want to have a class that has a list of attributes of different types that i want to be able to construct at runtime.
So my class would look something like:
class MyClass {
std::list<Attribute<?>*> attributes;
};
And my attribute template:
template<typename T>
class Attribute {
public:
Test(const T &t) : _t(t) {}
T getValue() const { return _t; }
void setValue(const T &t) { _t = t; }
private:
T _t;
};
int main() {
MyClass myClass;
myClass.attributes.push_back(new Attribute<int>(42));
myClass.attributes.push_back(new Attribute<double>(42.0));
}
As you can see the list of MyClass i put ? because that is my problem. I dont know how to make a list that will take different types of my Attribute template, i.e. int, double etc.
std::list<Attribute<?> *> attributes;
In Java, generics can be used for that. Is it possible in C++ to do this with somekind of construction? I tried using variadic templates but that doesnt seem to help solving my problem.
I need this but not in Java, in C++:
public class GenericAttribute<T> {
private T value;
public GenericAttribute (T value) {
setValue(value);
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
public static void main(String[] args) {
class Custom {
public Custom() {}
#Override public String toString() {
return "My custom object";
}
}
List<GenericAttribute<?>> attributes = new ArrayList<GenericAttribute<?>>();
attributes.add(new GenericAttribute<Integer>(1));
attributes.add(new GenericAttribute<Double>(3.1415926535));
attributes.add(new GenericAttribute<Custom>(new Custom()));
for (GenericAttribute<?> attr : attributes) {
System.out.println(attr.getValue());
}
}
Output:
1
3.1415926535
My custom object
Thanks for the help!
Version 3: Very Advanced (do not try that at home :D)
class Attribute {
private:
struct Head {
virtual ~Head() {}
virtual void *copy() = 0;
const type_info& type;
Head(const type_info& type): type(type) {}
void *data() { return this + 1; }
};
template <class T> struct THead: public Head {
THead(): Head(typeid(T)) {}
virtual ~THead() override { ((T*)data())->~T(); }
virtual void *copy() override {
return new(new(malloc(sizeof(Head) + sizeof(T)))
THead() + 1) T(*(const T*)data()); }
};
void *data;
Head *head() const { return (Head*)data - 1; }
void *copy() const { return data ? head()->copy() : nullptr; }
public:
Attribute(): data(nullptr) {}
Attribute(const Attribute& src): data(src.copy()) {}
Attribute(Attribute&& src): data(src.data) { src.data = nullptr; }
template <class T> Attribute(const T& src): data(
new(new(malloc(sizeof(Head) + sizeof(T))) THead<T>() + 1) T(src)) {}
~Attribute() {
if(!data) return;
Head* head = this->head();
head->~Head(); free(head); }
bool empty() const {
return data == nullptr; }
const type_info& type() const {
assert(data);
return ((Head*)data - 1)->type; }
template <class T>
T& value() {
if (!data || type() != typeid(T))
throw bad_cast();
return *(T*)data; }
template <class T>
const T& value() const {
if (!data || type() != typeid(T))
throw bad_cast();
return *(T*)data; }
template <class T>
void setValue(const T& it) {
if(!data)
data = new(new(malloc(sizeof(Head) + sizeof(T)))
THead<T>() + 1) T(it);
else {
if (type() != typeid(T)) throw bad_cast();
*(T*)data = it; }}
public:
static void test_me() {
vector<Attribute> list;
list.push_back(Attribute(1));
list.push_back(3.14);
list.push_back(string("hello world"));
list[1].value<double>() = 3.141592;
list.push_back(Attribute());
list[3].setValue(1.23f);
for (auto& a : list) {
cout << "type = " << a.type().name()
<< " value = ";
if(a.type() == typeid(int)) cout << a.value<int>();
else if (a.type() == typeid(double)) cout << a.value<double>();
else if (a.type() == typeid(string)) cout << a.value<string>();
else if (a.type() == typeid(float)) cout << a.value<float>();
cout << endl;
}
}
};
Output:
type = i value = 1
type = d value = 3.14159
type = Ss value = hello world
type = f value = 1.23
Explanation:
Attribute contains data pointer, which is initializaed by this strange placement new: new(new(malloc(sizeof(Head) + sizeof(T))) THead<T>() + 1) T(src) which first allocates enough room for the Head (should be 2*sizeof(void*) which should be just fine for any allignment of any architecture) and the type itself, constructs THead<T>() (initializes pointer to virtual method table and type info) and moves the pointer after the head = at the place we want data. The object is then constructed by another placement new using copy-constructor (or move-constructor) T(src). struct Head has two virtual functions - destructor and copy() which is implemented in THead<T> and used in Attribute(const Attribute&) copy-constructor. Finally ~Attribute() destructor calls ~Head() virtual destructor and releases the memory (if data != nullptr).
Version 1: Simple Attribute List
#include <vector>
#include <typeinfo>
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
class Attributes {
public:
typedef pair<const type_info&,void*> value_type;
typedef vector<value_type> vect;
typedef vect::const_iterator const_iterator;
template <class T>
void add(const T& value) {
data.push_back(pair<const type_info&,void*>(
typeid(T), new(malloc(sizeof(T))) T(value))); }
const_iterator begin() const {
return data.begin(); }
const_iterator end() const {
return data.end(); }
private:
vect data;
} attrs;
int main() {
attrs.add(1);
attrs.add(3.14);
for (auto a : attrs) {
cout << a.first.name() << " = ";
if(a.first == typeid(int))
cout << *(int*)a.second;
else if(a.first == typeid(double))
cout << *(double*)a.second;
cout << endl;
}
}
Output:
i = 1
d = 3.14
Version 2 (named attributes):
#include <string>
#include <unordered_map>
#include <typeinfo>
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
class Attributes {
public:
typedef pair<const type_info&,void*> value_type;
typedef unordered_map<string,value_type> map;
typedef map::const_iterator const_iterator;
template <class T>
bool add(const string& name, const T& value) {
auto it = data.insert(make_pair(
name, value_type(typeid(T), nullptr)));
if (!it.second) return false;
it.first->second.second = new(malloc(sizeof(T))) T(value);
return true; }
template <class T>
const T& get(const string& name) const {
auto it = data.at(name);
if (it.first != typeid(T)) throw bad_cast();
return *(T*)it.second; }
const_iterator begin() const {
return data.begin(); }
const_iterator end() const {
return data.end(); }
void erase(const_iterator it) {
free(it->second.second);
data.erase(it); }
bool remove(const string& name) {
auto it = data.find(name);
if (it == data.end()) return false;
free(it->second.second);
data.erase(it);
return true; }
private:
map data;
} attrs;
int main() {
attrs.add("one", 1);
attrs.add("pi", 3.14);
cout << "pi = " << attrs.get<double>("pi") << endl;
attrs.remove("pi");
for (auto a : attrs) {
cout << a.first << " = ";
if(a.second.first == typeid(int))
cout << *(int*)a.second.second;
else if(a.second.first == typeid(double))
cout << *(double*)a.second.second;
cout << endl;
}
}
Take a look at variant - this is a class that can be one of a number of different types, but you don't mind which until you need to operate on the values, in which case you can use the visitor pattern to visit all the types.
It is effectively a C++ type-aware version of the C 'union' construct but as it 'knows' which type was set, it can offer type safety.
The biggest issue with variants is that if you expose your implementation and allow any client to put pretty much any type into your variant (attributes.push_back(new Attribute<Widget>(myWidget));), you're going to be unable to do anything with it. E.g. if you want to do 'sum' on all the values put into your attributes, you'd need them to be convertible to a numeric representation and a Widget might not be.
The bigger question is what are you trying to do with them once you've captured these items as Attributes? Enumerating through them calling getValue() is going to give you different results depending on what types you put in. A visitor object would work, but it's still not clear what value this would bring.
It could be that you need something different, such as an interface, e.g. IAttribute that abstracts the underlying type as long as it conforms to the interface which has a getValueAsDouble() method or getValueAsString() method, which you could do to any type that got passes in - no need for variant or visitor in this case.
As Attribute<int> is different type than Attribute<double>, you can't use list or vector without creating a common base type.
Alternatively, you may store different type into a std::tuple.
Following may help:
template <typename ... Ts>
class MyClass {
public:
MyClass(const Ts&... args) : attributes(args...) {}
private:
std::tuple<Attribute<Ts>...> attributes;
};
int main()
{
MyClass<int, double> myClass(42, 42.0);
return 0;
}
As you already pointed out, in java it is much easier to do so because all classes extends java.lang.Object. In C(++), there is a similar way, but only for pointers - you can use void* for this. Your list will look something like this then:
std::list<Attribute<void*> *> attributes;
Sure, a void* doesn't save the type. If you need, add this field to your Attribute-class:
public:
std::type_info type;
Then, if you create an instance of Attributre, do this (probably from the constructor):
type = typeinfo(type_to_store);
Of corse, if you do so from the constructor, you'll need to run typeinfo in the code that calls the constructor.
Then, you can get the name of the class back from that field and the instance back from your void*:
std::string name = attribute->type_info.name();
void * instance = attribute->getValue();
What operations do you want to perform on this collection? Do you want to, say, call getValue on all of the Attribute<int> instances and ignore the others? In that case, a base class is fine—you just don’t make the getValue member function virtual (because its type depends on the subclass) and use RTTI to recover the type information at runtime:
struct AnyAttribute {
// Needs at least one virtual function to support dynamic_cast.
virtual ~AnyAttribute() {}
};
template<typename T>
struct Attribute : AnyAttribute { … };
int main() {
std::vector<AnyAttribute*> attributes;
attributes.push_back(new Attribute<int>(13));
attributes.push_back(new Attribute<int>(42));
attributes.push_back(new Attribute<double>(2.5));
for (const auto attribute : attributes) {
if (const auto int_attribute = dynamic_cast<Attribute<int>>(attribute)) {
std::cout << int_attribute->getValue() << '\n';
}
}
}
An obvious, but naive solution will be:
inherit Attribute<T> from base AttributeBase
store AttributeBase (smart-)pointers in container (downcast)
when reading container element, somehow figure out its type (RTTI)
cast back to derived Attribute<T> (upcast)
You can beautify this ugly solution by adding another level of indirection: make a generic container, that stores generic containers for each attribute, so casting will happen under the hood.
You can use integrated to language RTTI features, such as type_info but as far as I know, it's reliability is questionable. Better solution will be to wrap up some kind of static unique id to each Attribute<T> class and put an accessor to AttributeBase to retrieve it. You can add a typedef to relevant Attribute<T> to your unique id class to make casting easier.
So far so good, but in modern C++, we know, that when you need RTTI, it, probably, means that there is something wrong with your overall code design.
I don't know what exact task you have, but my "gut feelings" say me that you will probably can eliminate need of RTTI by using multiple dispatch (double dispatch), such as Visitor pattern in your code (they always say that when see RTTI).
Also, check some other tricks for inspiration:
More C++ Idioms/Coercion by Member Template

How to create a multiple typed object pool in C++

Im trying to create a system capable of allocating any type, and grouping same types together in arrays.
I want to be able to retrieve each array later using so I can iterate over each type.
Something like this:
ObjectDatabase
{
template<typename T>
T* Allocate();
template<typename T>
Array<T>& GetObjects();
}
My Array type is actually a pool so allocation/deletion is fast.
I thought about mapping each Array in a std::map using an int representing the type id for each T, but then each type T would need to inherit from a base class, so it can be stored in the map, and thus leading to casting when I iterate over the array.
I think this pattern has been done before but I'm not sure how.
Can someone help?
Update:
So I'm trying to basically create a structure like this:
struct ObjectDatabase
{
Array<Entities> mEntities;
Array<Transforms> mTransforms;
Array<Physics> mPhysics;
Array<Graphics> mGraphics;
}
But I wanted to somehow create the set of arrays at compile time.. using templates?
Then provide template functions to get access to each array, and to allocate from each array
You probably want to use templates to do type elision. Here's an example that may be similar to what you're looking for. The ObjectDatabase class uses templates and polymorphism internally to do type elision so the classes used don't have any constraints on them (other than the normal constraints for being placed in a standard library container).
#include <iostream>
#include <typeinfo>
#include <deque>
#include <map>
#include <cassert>
using namespace std;
struct ObjectDatabase {
ObjectDatabase() { }
template<typename T>
T &allocate() {
deque<T> &a = getObjects<T>();
a.push_back(T());
return a.back();
}
template<typename T>
deque<T> &getObjects() {
CollectionBase *&el = m_obdb[typeid(T).name()];
if ( not el )
el = new Collection<T>();
Collection<T> *elc = dynamic_cast<Collection<T>*>(el);
assert(elc);
deque<T> &a = elc->elements;
return a;
}
~ObjectDatabase() {
for ( ObDB::iterator i=m_obdb.begin(); i!=m_obdb.end(); ++i)
delete i->second;
}
private:
ObjectDatabase(ObjectDatabase const &);
ObjectDatabase &operator=(ObjectDatabase const &);
struct CollectionBase {
virtual ~CollectionBase() { }
};
template<typename T>
struct Collection : CollectionBase {
deque<T> elements;
};
typedef map<string, CollectionBase *> ObDB;
ObDB m_obdb;
};
struct Foo {
Foo() : name("Generic Foo") { }
char const *name;
};
struct Bar {
string name;
};
int main() {
ObjectDatabase obdb;
obdb.allocate<Foo>().name = "My First Foo";
obdb.allocate<Bar>().name = "My First Bar";
{
Foo &f = obdb.allocate<Foo>();
f.name = "My Second Foo";
Bar &b = obdb.allocate<Bar>();
b.name = "My Second Bar";
}
obdb.allocate<Foo>();
obdb.allocate<Bar>();
{
cout << "Printing Foo Names\n";
deque<Foo> &foos = obdb.getObjects<Foo>();
for ( deque<Foo>::iterator i = foos.begin(); i!=foos.end(); ++i )
cout << " -> " << i->name << "\n";
}
{
cout << "Printing Bar Names\n";
deque<Bar> &bars = obdb.getObjects<Bar>();
for ( deque<Bar>::iterator i = bars.begin(); i!=bars.end(); ++i )
cout << " -> " << i->name << "\n";
}
}
When I run this program, I get this output:
Printing Foo Names
-> My First Foo
-> My Second Foo
-> Generic Foo
Printing Bar Names
-> My First Bar
-> My Second Bar
->
This shows that the individual objects are stored in containers specific to their own type. You'll notice that Foo and Bar are nothing special, just regular aggregates. (Foo would even be a POD if it weren't for its default constructor.)
======== EDIT ========
If you don't want to use RTTI, you need to get rid of the typeid and dynamic_cast.
Getting rid of the dynamic_cast is fairly simple --- you don't actually need it. You can use static_cast instead; you just can't check that the derived type is correct with the assert() anymore. (But if the type was wrong, it would be a bug anyway.)
The typeid is a bit trickier, since that is used to construct an identifier to differentiate between different concrete types. But you can use some template magic and static objects to replace the string (from type_info::name()) with a simple void const * pointer:
template<typename T>
struct TypeTag {
static char const tag;
};
template<typename T>
char const TypeTag<T>::tag = '\0';
template<typename T>
void const *get_typemarker() {
return &TypeTag<T>::tag;
}
Now we can use get_typemarker<T>() to return a void const * key into the map. We change the type of ObDB's key from string to void const * and replace typeid(T).name() with get_typemarker<T>(). I've tested it and it gives the same output in my test program as the RTTI-enabled version.

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.
};

Store templated objects as member objects

suppose you have some code like this:
struct Manager
{
template <class T>
void doSomething(T const& t)
{
Worker<T> worker;
worker.work(t);
}
};
A "Manager" object is created once and called with a few diffent types "T", but each type T is called many times. This might be, in a simplified form, like
Manager manager;
const int N = 1000;
for (int i=0;i<N;i++)
{
manager.doSomething<int>(3);
manager.doSomething<char>('x');
manager.doSomething<float>(3.14);
}
Now profiling revealed that constructing a Worker<T> is a time-costly operation and it should be avoided to construct it N times (within doSomething<T>). For thread-safety reasons it is ok to have one Worker<int>, one Worker<char> and Worker<float> per "Manager", but not one Worker<int> for all Managers. So usually I would make "worker" a member variable. But how could I do this in the code above? (I do not know in advance which "T"s will be used).
I have found a solution using a std::map, but it is not fully typesafe and certainly not very elegant. Can you suggest a typesafe way without constructing Worker<T> more often than once per "T" without virtual methods?
(please note that Worker is not derived from any template-argument free base class).
Thanks for any solution!
You can use something like a std::map<std::type_info,shared_ptr<void> > like this:
#include <map>
#include <typeinfo>
#include <utility>
#include <functional>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;
// exposition only:
template <typename T>
struct Worker {
void work( const T & ) {}
};
// wrapper around type_info (could use reference_wrapper,
// but the code would be similar) to make it usable as a map<> key:
struct TypeInfo {
const type_info & ti;
/*implicit*/ TypeInfo( const type_info & ti ) : ti( ti ) {}
};
// make it LessComparable (could spcialise std::less, too):
bool operator<( const TypeInfo & lhs, const TypeInfo & rhs ) {
return lhs.ti.before( rhs.ti );
}
struct Manager
{
map<TypeInfo,shared_ptr<void> > m_workers;
template <class T>
Worker<T> * findWorker()
{
const map<TypeInfo,shared_ptr<void> >::const_iterator
it = m_workers.find( typeid(T) );
if ( it == m_workers.end() ) {
const shared_ptr< Worker<T> > nworker( new Worker<T> );
m_workers[typeid(T)] = nworker;
return nworker.get();
} else {
return static_cast<Worker<T>*>( it->second.get() );
}
}
template <typename T>
void doSomething( const T & t ) {
findWorker<T>()->work( t );
}
};
int main() {
Manager m;
m.doSomething( 1 );
m.doSomething( 1. );
return 0;
}
This is typesafe because we use type_info as an index into the map. Also, the workers are properly deleted even though they're in shared_ptr<void>s because the deleter is copied from the original shared_ptr<Worker<T> >s, and that one calls the proper constructor. It also doesn't use virtual functions, although all type erasure (and this is one) uses something like virtual functions somewhere. Here, it's in shared_ptr.
Factoring the template-independent code from findWorker into a non-template function to reduce code bloat is left as an exercise for the reader :)
Thanks to all commenters who pointed out the mistake of using type_info as the key directly.
You can add std::vector of boost::variants or boost::anys as member of your class. And append to it any worker you want.
EDIT: The code bellow will explain how
struct Manager
{
std::vector<std::pair<std::type_info, boost::any> > workers;
template <class T>
void doSomething(T const& t)
{
int i = 0;
for(; i < workers.size(); ++i)
if(workers[i].first == typeid(T))
break;
if(i == workers.size())
workers.push_back(std::pair<std::type_info, boost::any>(typeid(T).name(), Worker<T>());
any_cast<T>(workers[i]).work(t);
}
};
I was already working on an answer similar to mmutz's by time he posted his. Here's a complete solution that compiles and runs under GCC 4.4.3. It uses RTTI and polymorphism to lazily construct Worker<T>s and store them in a map.
#include <iostream>
#include <typeinfo>
#include <map>
struct BaseWorker
{
virtual ~BaseWorker() {}
virtual void work(const void* x) = 0;
};
template <class T>
struct Worker : public BaseWorker
{
Worker()
{
/* Heavyweight constructor*/
std::cout << typeid(T).name() << " constructor\n";
}
void work(const void* x) {doWork(*static_cast<const T*>(x));}
void doWork(const T& x)
{std::cout << typeid(T).name() << "::doWork(" << x << ")\n";}
};
struct TypeofLessThan
{
bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{return lhs->before(*rhs);}
};
struct Manager
{
typedef std::map<const std::type_info*, BaseWorker*, TypeofLessThan> WorkerMap;
~Manager()
{
// Delete all BaseWorkers in workerMap_
WorkerMap::iterator it;
for (it = workerMap_.begin(); it != workerMap_.end(); ++it)
delete it->second;
}
template <class T>
void doSomething(T const& x)
{
WorkerMap::iterator it = workerMap_.find(&typeid(T));
if (it == workerMap_.end())
{
it = workerMap_.insert(
std::make_pair(&typeid(T), new Worker<T>) ).first;
}
Worker<T>* worker = static_cast<Worker<T>*>(it->second);
worker->work(&x);
}
WorkerMap workerMap_;
};
int main()
{
Manager manager;
const int N = 10;
for (int i=0;i<N;i++)
{
manager.doSomething<int>(3);
manager.doSomething<char>('x');
manager.doSomething<float>(3.14);
}
}
map<std::type_info, BaseWorker*> doesn't work because type_info is not copy-constructible. I had do use map<const std::type_info*, BaseWorker*>. I just need to check that typeid(T) is guaranteed to always return the same reference (I think it is).
It doesn't matter whether or not typeid(T) returns the same reference, because I always use type_info::before do to all comparisons.
something like this will work:
struct Base { };
template<class T> struct D : public Base { Manager<T> *ptr; };
...
struct Manager {
...
Base *ptr;
};

OneOfAType container -- storing one each of a given type in a container -- am I off base here?

I've got an interesting problem that's cropped up in a sort of pass based compiler of mine. Each pass knows nothing of other passes, and a common object is passed down the chain as it goes, following the chain of command pattern.
The object that is being passed along is a reference to a file.
Now, during one of the stages, one might wish to associate a large chunk of data, such as that file's SHA512 hash, which requires a reasonable amount of time to compute. However, since that chunk of data is only used in that specific case, I don't want all file references to need to reserve space for that SHA512. However, I also don't want other passes to have to recalculate the SHA512 hash over and over again. For example, someone might only accept files which match a given list of SHA512s, but they don't want that value printed when the file reference gets to the end of the chain, or perhaps they want both, or... .etc.
What I need is some sort of container which contain only one of a given type. If the container does not contain that type, it needs to create an instance of that type and store it somehow. It's basically a dictionary with the type being the thing used to look things up.
Here's what I've gotten so far, the relevant bit being the FileData::Get<t> method:
class FileData;
// Cache entry interface
struct FileDataCacheEntry
{
virtual void Initalize(FileData&)
{
}
virtual ~FileDataCacheEntry()
{
}
};
// Cache itself
class FileData
{
struct Entry
{
std::size_t identifier;
FileDataCacheEntry * data;
Entry(FileDataCacheEntry *dataToStore, std::size_t id)
: data(dataToStore), identifier(id)
{
}
std::size_t GetIdentifier() const
{
return identifier;
}
void DeleteData()
{
delete data;
}
};
WindowsApi::ReferenceCounter refCount;
std::wstring fileName_;
std::vector<Entry> cache;
public:
FileData(const std::wstring& fileName) : fileName_(fileName)
{
}
~FileData()
{
if (refCount.IsLastObject())
for_each(cache.begin(), cache.end(), std::mem_fun_ref(&Entry::DeleteData));
}
const std::wstring& GetFileName() const
{
return fileName_;
}
//RELEVANT METHOD HERE
template<typename T>
T& Get()
{
std::vector<Entry>::iterator foundItem =
std::find_if(cache.begin(), cache.end(), boost::bind(
std::equal_to<std::size_t>(), boost::bind(&Entry::GetIdentifier, _1), T::TypeId));
if (foundItem == cache.end())
{
std::auto_ptr<T> newCacheEntry(new T);
Entry toInsert(newCacheEntry.get(), T::TypeId);
cache.push_back(toInsert);
newCacheEntry.release();
T& result = *static_cast<T*>(cache.back().data);
result.Initalize(*this);
return result;
}
else
{
return *static_cast<T*>(foundItem->data);
}
}
};
// Example item you'd put in cache
class FileBasicData : public FileDataCacheEntry
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
unsigned __int64 size;
public:
enum
{
TypeId = 42
}
virtual void Initialize(FileData& input)
{
// Get file attributes and friends...
}
DWORD GetAttributes() const;
bool IsArchive() const;
bool IsCompressed() const;
bool IsDevice() const;
// More methods here
};
int main()
{
// Example use
FileData fd;
FileBasicData& data = fd.Get<FileBasicData>();
// etc
}
For some reason though, this design feels wrong to me, namely because it's doing a whole bunch of things with untyped pointers. Am I severely off base here? Are there preexisting libraries (boost or otherwise) which would make this clearer/easier to understand?
As ergosys said already, std::map is the obvious solution to your problem. But I can see you concerns with RTTI (and the associated bloat). As a matter of fact, an "any" value container does not need RTTI to work. It is sufficient to provide a mapping between a type and an unique identifier. Here is a simple class that provides this mapping:
#include <stdexcept>
#include <boost/shared_ptr.hpp>
class typeinfo
{
private:
typeinfo(const typeinfo&);
void operator = (const typeinfo&);
protected:
typeinfo(){}
public:
bool operator != (const typeinfo &o) const { return this != &o; }
bool operator == (const typeinfo &o) const { return this == &o; }
template<class T>
static const typeinfo & get()
{
static struct _ti : public typeinfo {} _inst;
return _inst;
}
};
typeinfo::get<T>() returns a reference to a simple, stateless singleton which allows comparisions.
This singleton is created only for types T where typeinfo::get< T >() is issued anywhere in the program.
Now we are using this to implement a top type we call value. value is a holder for a value_box which actually contains the data:
class value_box
{
public:
// returns the typeinfo of the most derived object
virtual const typeinfo& type() const =0;
virtual ~value_box(){}
};
template<class T>
class value_box_impl : public value_box
{
private:
friend class value;
T m_val;
value_box_impl(const T &t) : m_val(t) {}
virtual const typeinfo& type() const
{
return typeinfo::get< T >();
}
};
// specialization for void.
template<>
class value_box_impl<void> : public value_box
{
private:
friend class value_box;
virtual const typeinfo& type() const
{
return typeinfo::get< void >();
}
// This is an optimization to avoid heap pressure for the
// allocation of stateless value_box_impl<void> instances:
void* operator new(size_t)
{
static value_box_impl<void> inst;
return &inst;
}
void operator delete(void* d)
{
}
};
Here's the bad_value_cast exception:
class bad_value_cast : public std::runtime_error
{
public:
bad_value_cast(const char *w="") : std::runtime_error(w) {}
};
And here's value:
class value
{
private:
boost::shared_ptr<value_box> m_value_box;
public:
// a default value contains 'void'
value() : m_value_box( new value_box_impl<void>() ) {}
// embedd an object of type T.
template<class T>
value(const T &t) : m_value_box( new value_box_impl<T>(t) ) {}
// get the typeinfo of the embedded object
const typeinfo & type() const { return m_value_box->type(); }
// convenience type to simplify overloading on return values
template<class T> struct arg{};
template<class T>
T convert(arg<T>) const
{
if (type() != typeinfo::get<T>())
throw bad_value_cast();
// this is safe now
value_box_impl<T> *impl=
static_cast<value_box_impl<T>*>(m_value_box.get());
return impl->m_val;
}
void convert(arg<void>) const
{
if (type() != typeinfo::get<void>())
throw bad_value_cast();
}
};
The convenient casting syntax:
template<class T>
T value_cast(const value &v)
{
return v.convert(value::arg<T>());
}
And that's it. Here is how it looks like:
#include <string>
#include <map>
#include <iostream>
int main()
{
std::map<std::string,value> v;
v["zero"]=0;
v["pi"]=3.14159;
v["password"]=std::string("swordfish");
std::cout << value_cast<int>(v["zero"]) << std::endl;
std::cout << value_cast<double>(v["pi"]) << std::endl;
std::cout << value_cast<std::string>(v["password"]) << std::endl;
}
The nice thing about having you own implementation of any is, that you can very easily tailor it to the features you actually need, which is quite tedious with boost::any. For example, there are few requirements on the types that value can store: they need to be copy-constructible and have a public destructor. What if all types you use have an operator<<(ostream&,T) and you want a way to print your dictionaries? Just add a to_stream method to box and overload operator<< for value and you can write:
std::cout << v["zero"] << std::endl;
std::cout << v["pi"] << std::endl;
std::cout << v["password"] << std::endl;
Here's a pastebin with the above, should compile out of the box with g++/boost: http://pastebin.com/v0nJwVLW
EDIT: Added an optimization to avoid the allocation of box_impl< void > from the heap:
http://pastebin.com/pqA5JXhA
You can create a hash or map of string to boost::any. The string key can be extracted from any::type().