Allow map to accept int, bool and string as values [duplicate] - c++

I want to put two (not more) different data types as values into a map as shown in the following example:
typeX A, B, ...;
typeY Z, Y, ...;
void func (typeX) { ... }
void func (typeY) { ... }
std::map <std::string, what_to_put_here??> map;
map["a"] = A;
map["z"] = Z;
...
std::vector<std::string> list;
// This list will be something like "a", "y", ...
for (unsigned int i = 0; i < list.size(); ++i)
func( map[list[i]] )
Obviously this doesn't work, as the map will only accept one data type of value. However, when looping over list, the call to func() should be unambiguous since the type of map[list[i]] is known.
I want to avoid explicit casting or type checking, i.e. something like this:
if (typeid( map[list[i]] ).name() == "typeX")
func( map[list[i]] )
else if (typeid( map[list[i]] ).name() == "typeY")
func( map[list[i]] )
Is this possible? Again, it will be limited to only two different data types.

You want to use boost::variant:
std::map <std::string, boost::variant<typeX, typeY>>

Are typeX and typeY subclasses of a typeBase class ?
If so, you could do a std::map<std::string,typeBase*> to store both typeX* and typeY* in the map.

With some metaprogramming you can easily build an heterogenous map which can store any type from a given set of types. Here is an example which does this, without type erasure nor the need to visit the values.

One way to implement a multi-type map is by using the nifty features of std::tuple in C++11, which allows access by a type key. You can wrap this to create access by arbitrary keys. An in-depth explanation of this (and quite an interesting read) is available here:
https://jguegant.github.io/blogs/tech/thread-safe-multi-type-map.html

If you don't want to use Boost, then I think building a class hierarchy as proposed by rom1504 makes sense. I would implement an abstract base class with func() as member function as follows:
class Base {
public:
virtual void func() = 0;
};
void Base::func() {};
Then, I would turn your typeX and typeY data types into subclasses by deriving from Base as follows:
class typeX : public Base {
public:
void func() { std::cout << "typeX::func()" << std::endl; };
int i; // Example for your original 'typeX' content.
};
class typeY : public Base {
public:
void func() { std::cout << "typeY::func()" << std::endl; };
std::string s; // Example for your original 'typeY' content.
};
Here, the func() implementations would take the content of your corresponding global func() functions. Next, your map needs to store pointers to Base as value:
std::map<std::string, Base*> map;
map["a"] = &A;
map["z"] = &Z;
As a result, you can implement your loop as follows (using a C++11 range-based for loop):
for (auto const &list_item : list)
map[list_item]->func();
Notes:
In case you use dynamically created instances of typeX and typeY, you should prefer to store smart pointers in the map, such as std::unique_ptr or std::shared_ptr, to ease memory management.
If you have to stick to your global func() functions, then you can call them from the corresponding member functions. I would just turn the parameter into a pointer or reference to avoid copying objects.
Full code on Ideone

This would probably be extreme overkill, but QT has a variable called QVariant which can be used to map to different types of (QT) variables.
Documentation here: http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html

You need a type erasure.
Type erasure is a pattern that hides the underlying type, such known examples are boost::any, but keep in mind that boost any has a dynamic polymorphic behavior (dynamic dispatch at runtime). boost::variant on the other hand is another example and uses template metaprogramming techniques. see variant vs any
The simplest solution though, could be writing your own class type erasure with an enum for the underlying type.

Related

C++ template value in std::map [duplicate]

I want to put two (not more) different data types as values into a map as shown in the following example:
typeX A, B, ...;
typeY Z, Y, ...;
void func (typeX) { ... }
void func (typeY) { ... }
std::map <std::string, what_to_put_here??> map;
map["a"] = A;
map["z"] = Z;
...
std::vector<std::string> list;
// This list will be something like "a", "y", ...
for (unsigned int i = 0; i < list.size(); ++i)
func( map[list[i]] )
Obviously this doesn't work, as the map will only accept one data type of value. However, when looping over list, the call to func() should be unambiguous since the type of map[list[i]] is known.
I want to avoid explicit casting or type checking, i.e. something like this:
if (typeid( map[list[i]] ).name() == "typeX")
func( map[list[i]] )
else if (typeid( map[list[i]] ).name() == "typeY")
func( map[list[i]] )
Is this possible? Again, it will be limited to only two different data types.
You want to use boost::variant:
std::map <std::string, boost::variant<typeX, typeY>>
Are typeX and typeY subclasses of a typeBase class ?
If so, you could do a std::map<std::string,typeBase*> to store both typeX* and typeY* in the map.
With some metaprogramming you can easily build an heterogenous map which can store any type from a given set of types. Here is an example which does this, without type erasure nor the need to visit the values.
One way to implement a multi-type map is by using the nifty features of std::tuple in C++11, which allows access by a type key. You can wrap this to create access by arbitrary keys. An in-depth explanation of this (and quite an interesting read) is available here:
https://jguegant.github.io/blogs/tech/thread-safe-multi-type-map.html
If you don't want to use Boost, then I think building a class hierarchy as proposed by rom1504 makes sense. I would implement an abstract base class with func() as member function as follows:
class Base {
public:
virtual void func() = 0;
};
void Base::func() {};
Then, I would turn your typeX and typeY data types into subclasses by deriving from Base as follows:
class typeX : public Base {
public:
void func() { std::cout << "typeX::func()" << std::endl; };
int i; // Example for your original 'typeX' content.
};
class typeY : public Base {
public:
void func() { std::cout << "typeY::func()" << std::endl; };
std::string s; // Example for your original 'typeY' content.
};
Here, the func() implementations would take the content of your corresponding global func() functions. Next, your map needs to store pointers to Base as value:
std::map<std::string, Base*> map;
map["a"] = &A;
map["z"] = &Z;
As a result, you can implement your loop as follows (using a C++11 range-based for loop):
for (auto const &list_item : list)
map[list_item]->func();
Notes:
In case you use dynamically created instances of typeX and typeY, you should prefer to store smart pointers in the map, such as std::unique_ptr or std::shared_ptr, to ease memory management.
If you have to stick to your global func() functions, then you can call them from the corresponding member functions. I would just turn the parameter into a pointer or reference to avoid copying objects.
Full code on Ideone
This would probably be extreme overkill, but QT has a variable called QVariant which can be used to map to different types of (QT) variables.
Documentation here: http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html
You need a type erasure.
Type erasure is a pattern that hides the underlying type, such known examples are boost::any, but keep in mind that boost any has a dynamic polymorphic behavior (dynamic dispatch at runtime). boost::variant on the other hand is another example and uses template metaprogramming techniques. see variant vs any
The simplest solution though, could be writing your own class type erasure with an enum for the underlying type.

Implementing an any container

I'm well aware of boost::any and boost::variant, but in this instance they don't fit my needs.
Normally, to contain an object of unknown type, one would derive it from a common base and access the instance through virtual methods. But, what can one do if it's impossible to use a common base?
I know that in this example you would have to know the contained type, but bear with me. std::vector is a template class with top level class also being a template. As far as I know it cannot be given a non-template base without modifying the STL headers. Now, lets say I want to create a vector of a single type but the containing class doesn't care about the type, but it does require access to some of the 'common' methods, size() and pop_back() for example.
Using boost::any, the type has been erased, making it almost impossible to dereference the contained object. boost::variant and tuple require knowing before hand what types may be inserted, causing the containing class to itself be a template.
What I have so far is something like this:
struct container
{
virtual ~container() = 0;
virtual void pop_back() = 0;
virtual size_t size() = 0;
...
}
template < typename T >
struct contained
{
std::vector< T > _vec;
contained ( size_t n, T _what ) : _vec( n, _what ) {}
virtual void pop_back() { _vec.pop_back(); }
...
}
class some_class
{
container* _cont;
template < typename T >
void create ( T _first ) { _cont = new contained< T >(1,_first); }
...
}
Here the client can call on create() and the template parameter should be determined automatically. Not a great example I know, but I'm trying to hide the template parameters from the client. Without doing this, some_class would have to also keep track of what type is being stored.
My method relies on virtual calls which causes a performance loss, especially when the internal class has virtual methods of it's own.
Are there any other types of containers that would better suit my needs?
Ideally, I'd like something like this
container = std::vector< T >;
container.pop_back();
container.push_back( T2 ); // compile error if types don't match
Where internally it would track the type and do a simple cast rather than rely on virtual methods. Almost like auto with the difference being that once declared it's type can change.
Edit:
In reality, I want to create a wrapper around std::basic_filebuf. This wrapper class opens the file with char,wchar_t or unsigned long based on the BOM. The wrapper is also derived from basic_filebuf with the template parameter being whatever the client chooses. Internally, it converts unicode code points from the file to the clients desired encoding. The problem arises when storing the internal basic_filebuf because it can be declared with any type as the template parameter. I don't want to use template specialization because I want the client to be able to pass in their own basic_filebuf instance.
Must be VS2010 compatible, which has limited features from C++11.
This cannot be combined with compile-time type checking. Based on your "ideally" example:
container c;
if (thingKnownAtRunTime()) {
c = vector<int>;
} else {
c = vector<string>;
}
c.push_back("hello world");
For the filebuf case, though, you might get good enough with something like (warning: untested)
template<typename FILEBUF>
void gensputc(FILEBUF* fb, long long c) {
FILEBUf::char_type c2 = smart_convert<FILEBUf::char_type>(c);
fb->sputc(c2);
}
class FileBufWrapper {
public:
template<typename FILEBUF> FileBufWrapper(FILEBUF* fb) {
fb_ = fb;
sputc_ = gensputc<FILEBUF>;
}
void sputc(long long c) {
sputc_(fb_,c);
}
private:
typedef void(*sputc_t)(void*, long long);
sputc_t sputc_;
void* fb_;
};
The smart_convert function throws a runtime exception if the value cannot be converted to the char type. Also, this needs to be done for every function you intend to call.
If you have access to c++11's std::function and std::bind, this can be made a little cleaner, especially for the cases where you don't need to convert anything.

C++ One std::vector containing template class of multiple types

I need to store multiple types of a template class in a single vector.
Eg, for:
template <typename T>
class templateClass{
bool someFunction();
};
I need one vector that will store all of:
templateClass<int> t1;
templateClass<char> t2;
templateClass<std::string> t3;
etc
As far as I know this is not possible, if it is could someone say how?
If it isn't possible could someone explain how to make the following work?
As a work around I tried to use a base, non template class and inherit the template class from it.
class templateInterface{
virtual bool someFunction() = 0;
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction();
};
I then created a vector to store the base "templateInterface" class:
std::vector<templateInterface> v;
templateClass<int> t;
v.push_back(t);
This produced the following error:
error: cannot allocate an object of abstract type 'templateInterface'
note: because the following virtual functions are pure within 'templateInterface'
note: virtual bool templateInterface::someFunction()
To fix this error I made the function in templateInterface not a pure virtual by providing a function body, this compiled but when calling the function the overide is not used, but instead the body in the virtual function.
Eg:
class templateInterface{
virtual bool someFunction() {return true;}
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction() {return false;}
};
std::vector<templateInterface> v;
templateClass<int> i;
v.push_back(i);
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body
Is there any way to fix this so that the overridden function is used, or is there another workaround to store multiple template types in a single vector?
Why your code doesn't work:
Calling a virtual function on a value doesn't use polymorphism. It calls the function which is defined for the type of this exact symbol as seen by the compiler, not the runtime type. When you insert sub types into a vector of the base type, your values will be converted into the base type ("type slicing"), which is not what you want. Calling functions on them will now call the function as defined for the base type, since not it is of that type.
How to fix this?
The same problem can be reproduced with this code snippet:
templateInterface x = templateClass<int>(); // Type slicing takes place!
x.someFunction(); // -> templateInterface::someFunction() is called!
Polymorphism only works on a pointer or reference type. It will then use the runtime type of the object behind the pointer / reference to decide which implementation to call (by using it's vtable).
Converting pointers is totally "safe" with regard to type slicing. Your actual values won't be converted at all and polymorphism will work as expected.
Example, analogous to the code snippet above:
templateInterface *x = new templateClass<int>(); // No type slicing takes place
x->someFunction(); // -> templateClass<int>::someFunction() is called!
delete x; // Don't forget to destroy your objects.
What about vectors?
So you have to adopt these changes in your code. You can simply store pointers to actual types in the vector, instead of storing the values directly.
When working with pointers you also have to care about deleting your allocated objects. For this you can use smart pointers which care about deletion automatically. unique_ptr is one such smart pointer type. It deletes the pointee whenever it goes out of scope ("unique ownership" - the scope being the owner). Assuming the lifetime of your objects is bound to the scope this is what you should use:
std::vector<std::unique_ptr<templateInterface>> v;
templateClass<int> *i = new templateClass<int>(); // create new object
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector
v.emplace_back(new templateClass<int>()); // "direct" alternative
Then, call a virtual function on one of these elements with the following syntax:
v[0]->someFunction();
Make sure you make all functions virtual which should be possible to be overridden by subclasses. Otherwise their overridden version will not be called. But since you already introduced an "interface", I'm sure you are working with abstract functions.
Alternative approaches:
Alternative ways to do what you want is to use a variant type in the vector. There are some implementations of variant types, the Boost.Variant being a very popular one. This approach is especially nice if you don't have a type hierarchy (for example when you store primitive types). You would then use a vector type like std::vector<boost::variant<int, char, bool>>
Polymorphism only works through pointers or references. You'll
need the non-template base. Beyond that, you'll need to decide
where the actual objects in container will live. If they're all
static objects (with sufficient lifetime), just using
a std::vector<TemplateInterface*>, and inserting with
v.push_back(&t1);, etc., should do the trick. Otherwise,
you'll probably want to support cloning, and keep clones in the
vector: preferably with Boost pointer containers, but
std::shared_ptr can be used as well.
The solutions given so far are fine though be aware that in case you were returning the template type other than bool in your example , none of these would help as the vtable slots would not be able to be measured before hand. There are actually limits , from a design point of view , for using a template oriented polymorphic solution.
Solution nr. 1
This solution inspired by Sean Parent's C++ Seasoning talk. I highly recommend to check it out on youtube. My solution simplified a bit and the key is to store object in method itself.
One method only
Create a class that will invoke method of stored object.
struct object {
template <class T>
object(T t)
: someFunction([t = std::move(t)]() { return t.someFunction(); })
{ }
std::function<bool()> someFunction;
};
Then use it like this
std::vector<object> v;
// Add classes that has 'bool someFunction()' method
v.emplace_back(someClass());
v.emplace_back(someOtherClass());
// Test our vector
for (auto& x : v)
std::cout << x.someFunction() << std::endl;
Several methods
For several methods use shared pointer to share object between methods
struct object {
template <class T>
object(T&& t) {
auto ptr = std::make_shared<std::remove_reference_t<T>>(std::forward<T>(t));
someFunction = [ptr]() { return ptr->someFunction(); };
someOtherFunction = [ptr](int x) { ptr->someOtherFunction(x); };
}
std::function<bool()> someFunction;
std::function<void(int)> someOtherFunction;
};
Other types
Primitive types (such as int, float, const char*) or classes (std::string etc.) may be wrapped in the same way as object class do but behave differently. For example:
struct otherType {
template <class T>
otherType(T t)
: someFunction([t = std::move(t)]() {
// Return something different
return true;
})
{ }
std::function<bool()> someFunction;
};
So now it is possible to add types that does not have someFunction method.
v.emplace_back(otherType(17)); // Adding an int
v.emplace_back(otherType("test")); // A string
Solution nr. 2
After some thoughts what we basically done in first solution is created array of callable functions. So why not just do the following instead.
// Example class with method we want to put in array
struct myclass {
void draw() const {
std::cout << "myclass" << std::endl;
}
};
// All other type's behaviour
template <class T>
void draw(const T& x) {
std::cout << typeid(T).name() << ": " << x << std::endl;
}
int main()
{
myclass x;
int y = 17;
std::vector<std::function<void()>> v;
v.emplace_back(std::bind(&myclass::draw, &x));
v.emplace_back(std::bind(draw<int>, y));
for (auto& fn : v)
fn();
}
Conclusion
Solution nr. 1 is definitely an interesting method that does not require inheritance nor virtual functions. And can be used to other stuff where you need to store a template argument to be used later.
Solution nr. 2, on the other hand, is simpler, more flexible and probably a better choice here.
If you're looking at a container to store multiple types, then you should explore boost variant from the popular boost library.

creating in c++ a vector of templates whose type is unknown (void templates)

I have a C++ template class that contains a method pointer and a class pointer, and who has single method, call, that calls the method pointer on the class pointer.
This template is called Method< C >, C being the class of the class and method pointers.
I want to create an array (std::vector) of this template, but I want this vector to be able to contain different classes of this template. My final goal is to go through this vector and call the call method of each of the elements, even if they have different classes.
How would you do that?
You can not store templates in vector, only objects that have types. And template become type when it is instantiated.
So, you can't do exactly what you want.
I recommend you use function and bind. See an example:
struct A
{
void call()
{
std::cout << "hello";
}
};
int main()
{
std::vector <std::function<void()>> v;
v.push_back(std::bind(&A::call, A()));
for (auto it = v.begin(); it != v.end(); ++it) {
(*it)();
}
return 0;
}
It does exactly you want.
If the methods all have the same signature (with respect to the input parameters and return type) then you could wrap them in std::function objects and store those in the vector. Either way, it sounds like you'll need to wrap your class in some sort of polymorphic type (or derive them from a common, non-templated base -- but then you'll have reinvented std::function.)
The bottom line here is that std::vector cannot be made to store heterogeneous types.

Type erasure for methods with differing in return types

I was wondering if some form of type erasure exists for dealing with methods that have the same name and arguments but return different values like in my example below (begin and end). I'm not planning on actually using this anywhere I'm just interested in knowing if it's possible, and, if so, how it would be done.
The only form of type erasure I know about is having a pointer to a pure virtual concept class which points to a model<T> which forwards calls to the underlying T. However, this requires that all the T's contain methods with the exact same signature, while in my example the return types differ. As far as I can tell something akin to virtual template functions would be needed to do what I'm asking, but I may be missing something.
class Iterable
{
//how would this be defined?
}
int main(int argc, char *argv[])
{
vector<int> v = {1, 2, 3, 4, 5};
set<string> s = {"foo", "bar", "baz"};
Iterable iterable;
if(argc == 2) iterable = v;
else iterable = s;
for(auto val : it)
{
cout << val << ' ';
}
}
Type erasure can and has been implemented in C++ in different contexts. The most common approach, which is used in boost::any, std::function< signature >, std::thread and others is based on a non-polymorphic class that is the type erased object, which contains a pointer to an interface type. Internally, during construction, assignment or whenever the user type is erased, an implementation of the interface is instantiated and stored.
As a motivating simplified example, consider that we wanted to create a printable type that can be used to print any type that implements operator<< to std::cout using type erasure. For that we need the type printable, the internal interface printable_impl_base, and the actual implementations:
// regular polymorphic hierarchy:
struct printable_impl_base {
virtual ~printable_impl_base() {}
virtual void print() const = 0;
};
template <typename T>
struct printable_impl : printable_impl_base {
T copy_to_print;
printable_impl( T const & o ) : copy_to_print( o ) {}
virtual void print() const {
std::cout << copy_to_print << std::endl;
}
};
// type erasure is performed in printable:
class printable {
std::shared_ptr<printablable_impl_base> p;
public:
template <typename T>
printable( T obj ) : p( new printable_impl<T>(obj) ) {}
void print() const {
p->print();
}
};
Note that the pattern is very similar to a regular polymorphic hierarchy, with the difference that an interface object is added that is a value type (borrowing the term value type from C#), that holds the actual polymorphic objects inside.
Looking at it this way, it seems kind of simplistic and useless, but that is the fuel that drives boost::any (the internal interface is only a typeid), std::function< void () > (the internal interface is that it implements void operator()), or shared_ptr<> (the interface is the deleter method, that relinquishes the resource).
There is one specific different type of type erasure when the only thing that needs to be done with the type that implements type erasure is to destroy it: use a temporary and bind it to a constant reference... But this is very specific, if you want you can read about it here: http://drdobbs.com/cpp/184403758
In the specific case that you are talking about in the question it is a bit more complex, because you don't want to erase a single type, but rather a couple of them. The Iterable interface must erase the type of the container that it internally holds, and in doing so it has to provide it's own iterators that have to perform type erasure on the iterators from the container. Still, the idea is basically the same, just more work to do to implement.
You may be interested in boost::any:
http://www.boost.org/doc/libs/1_46_1/doc/html/any.html
The C++ Standard library does not support run-time variance in it's container types. There's nothing wrong with implementing this, however, the memory management without garbage collection at the language level is going to be ick-tastic and you're going to have fun making it performant.
What's worth mentioning is that in some STL implementations, they implement something known as SCARY iteration, where vector<int, std::allocator<int>>::iterator is the same type as vector<int, mycustomallocator<int>>::iterator.
In addition, you need to be very careful. A vector is definitely RandomAccessIterable, but a set is only ConstIterable and is definitely not RandomAccessIterable, and an InputIterator is only ForwardIterable. You would have to define templates for all of these scenarios.