First, I really like the pattern of lazy initialization of singletons. I use it in the following way to get different kind of data with varying value types (The example is simplified):
class A
{
template<typename T>
const T& getData() const
{
static T data;
return data;
}
}
I know that the data variable is not connected to any instances of the class and that it exists until the program ends.
But what I want now, is that each instance of the class A should hold the variables in a non-static way and still there should be the flexibility of calling .getData<bool>() or with any other data type, without the need to specify each possible data type in the class definition.
Is that possible? I have not come up with an idea to implement that.
I thought of something with a container like:
template<A*, typename T>
class DataContainer
{
T data;
}
With that one can extend the code to:
class A
{
template<typename T>
const T& getData() const
{
static DataContainer<this, T> container;
return container.data;
}
}
But that does not compile.
Does anybody of you have an idea how to implement that?
Here's one idea, using Boost.any:
#include <typeinfo>
#include <type_index>
#include <unordered_map>
#include <boost/any.hpp>
struct ThingGetter
{
template <typename T>
T & get()
{
auto key = std::type_index(typeid(T));
auto it = things.find(key);
if (it == things.end())
{
it = things.emplace(key, boost::any(T())).first;
}
return boost::any_cast<T&>(*it);
}
std::unordered_map<std::type_index, boost::any> things;
};
This simple version assumes that each type can be value-initialized and creates a value-initialized value if no entry for the requested type exists. Alternative implementations could return a pointer that might be null and have a separate insertion interface.
Usage:
ThingGetter mythings;
mythings.get<bool>() = true;
mythings.get<double>() = 1.5;
return mythings.get<int>();
Related
I have a class called DBDriver that handles communication with a given table in a database. Its public entry point is a function template called execute_query(), which executes SELECT queries. Upon calling this function, some database logic is performed, and then a provided container (of the template type) is populated with results. This looks something like the following:
class DBDriver {
...
template <typename CONT_T>
void execute_query(const std::string& query, CONT_T& container);
...
};
template <typename CONT_T>
void DBDriver::execute_query(const std::string& query, CONT_T& container) {
DBCursor& cursor = ... // some database logic here
populate_container(container, cursor);
}
Of course, the above will not compile, as populate_container() is not defined in DBDriver.
DBDriver should be purely virtual and have several classes derive from it (one for each database table involved). Each derived class will define its own overloads of populate_container(), one for each relevant container type. This will look something like the following:
class SampleTableDBDriver : public DBDriver {
// ...
populate_container(const ContainerTypeOne& container, DBCursor& cursor);
populate_container(const ContainerTypeTwo& container, DBCursor& cursor);
// ...
};
My original attempt at this was unsuccessful, as I would have needed to define a virtual function template in DBDriver to serve as an entry point to a derived class' populate_container() overloads. (Of course such a thing does not exist in C++, hence my issue.)
Is there a cleaner, idiomatic solution for this type of problem?
The reason why execute_query is a template function is you need a generic container. What if you define a Interface for the container?
class IContainer
{};
Template Functions cannot be virtual. Therefore, you can use the Template Method Design Pattern.
class DBDriver
{
public:
void execute_query(const std::string& query, IContainer **_ppContainer);
{
DBCursor& cursor = ... // some database logic here
populate_container(_ppContainer, cursor);
}
virtual void populate_container(IContainer **_ppContainer, DBCursor &_dbCursor) = 0;
};
And let every derived class implement populate_container and also provide their custom Container.
class SampleTableDBDriver : public DBDriver
{
public:
class ContainerTypeOne : public IContainer
{};
void populate_container(IContainer **_ppContainer, DBCursor &_dbCursor)
{
ContainerTypeOne *pContainer = new ContainerTypeOne();
//....
(*_ppContainer) = pContainer;
}
};
SampleTableDBDriver oSampleDriver;
IContainer *pContainer = NULL;
std::string szQuery = // some query ;
oSampleDriver.execute_query(szQuery, &pContainer);
if(pContainer != NULL)
{
SampleTableDBDriver::ContainerTypeOne *pSampleDriverContainer =
dynamic_cast<SampleTableDBDriver::ContainerTypeOne*>(pContainer);
//use pSampleDriverContainer
}
Edit: For supporting multiple containers.
In your original design the populate_container seems to be overloaded in derived classes. In that case you would still pass the exact container from outside while calling execute_query.
Same thing can be done with this Template Method design. Then, you will need to decipher the type of container inside the populate_container function as follows:
New signature : int populate_container(IContainer *_pContainer, DBCursor &_dbCursor)
int populate_container(IContainer *_pContainer, DBCursor &_dbCursor)
{
if(dynamic_cast<ContainerTypeOne *>(_pContainer) != NULL)
{
ContainerTypeOne *pContainerOne = _pContainer;
//populate the result by using pContainerOne
return 1;
}
if(dynamic_cast<ContainerTypeTwo *>(_pContainer) != NULL)
{
ContainerTypeOne *pContainerTwo = _pContainer;
//populate the result by using pContainerTwo
return 1;
}
//no, I do not support the container you passed.
return 0;
}
SampleTableDBDriver oSampleDriver;
SampleTableDBDriver::ContainerTypeOne oSampleContainerTypeOne;
std::string szQuery = // some query ;
if(oSampleDriver.execute_query(szQuery, &oSampleContainerTypeOne) != 0)
{
//use oSampleContainerTypeOne;
}
You have options to choose from:
If you don't need populate_container() to be a member of DBDriver and can extend (or define) container interface, just implement
ContainerTypeOne::populate(DBCursor& cursor);
Make populate_container() a friend (in case you need access to private members of DBDriver):
template <typename CONT_T> friend void execute_query(const std::string& query, CONT_T& container);
Make populate_container() a non-member template function (if you don't need access to private members of DBDriver)
One way to do this is to employ the separation of concerns principle.
Querying databases goes to its own class hierarchy, and populating container goes to its own separate class hierarchy. These two hierarchies know nothing about each other, e.g. DBDriverThirteen knows nothing about ContainerFortyTwo. The two hierarchies only touch at their roots, i.e. DBDriver (and so its every derived class) knows about IContainerPopulator but nothing about any specific containers.
You may have a template that builds a specific ContainerPopulator for each container type. Assume for simplicity that you only need to support standard containers of strings that implement push_back.
struct IContainerPopulator {
virtual void push_back(const std::string&) = 0;
};
template <class CONT_T>
struct ContainerPopulator : IContainerPopulator {
StandardContainerPopulator (CONT_T& cont) : cont(cont) {}
void push_back(const std::string& s) override { cont.push_back(s); }
private:
CONT_T& cont;
};
Now you can do this
template <typename CONT_T>
void execute_query(const std::string& query, CONT_T& container) {
execute_query_adapted(query, ContainerPopulator<CONT_T>(container));
}
// no template!
virtual void execute_query_adapted(const std::string&,
IContainerPopulator&&) = 0;
By now you have probably recognised that IContainerPopulator is nothing but a specialised poor man's function binder. Why write another one if we have pretty good support in the language and its standard library? If you only need to support push_back, you can alternatively do this:
template <typename CONT_T>
void execute_query(const std::string& query, CONT_T& container) {
execute_query_adapted2(query,
[&](const std::string& s){container.push_back(s);});
}
// no template
virtual void execute_query_adapted2(const std::string&,
std::function<void(const std::string&)>) = 0;
Now if you need more than just push_back (or any fixed set of functions) and/or more than std::string (or any fixed set of types), things can get really hairy. More information would be needed about potential implementations of populate_query.
As long as you don't mind using RTTI (or Boost.TypeIndex, which doesn't require RTTI), you can use type erasure and void* to get what you want. It's a bit dirty, but it does the job.
#include <functional>
#include <typeindex>
#include <unordered_map>
class driver {
public:
template <typename Container, typename Populator>
void register_populator(Populator populator) {
populators[type_index<Container>()] = [populator](void* v) {
Container& container = *static_cast<Container*>(v);
populator(container);
};
}
template <typename Container>
void execute(Container& container) {
auto it = populators.find(type_index<Container>());
if (it != populators.end()) {
it->second(&container);
}
}
private:
template <typename T>
static std::type_index type_index() {
return std::type_index(typeid(std::remove_cv_t<T>));
}
std::unordered_map<std::type_index, std::function<void (void*)>> populators;
};
Then use like so:
#include <vector>
#include <iostream>
int main() {
driver d;
d.register_populator<std::vector<int>>([](std::vector<int>&) {
std::cout << "Populate vector<int>\n";
});
d.register_populator<std::vector<float>>([](std::vector<float>&) {
std::cout << "Populate vector<float>\n";
});
std::vector<int> int_vector;
std::vector<float> float_vector;
d.execute(int_vector);
d.execute(float_vector);
}
Output:
Populate vector<int>
Populate vector<float>
I'm trying to create a statistics system in C++ which will allow me to associate a string with a value of an arbitrary type. Currently, I have it working with an enum that keeps track of the type and a void * that points to the object, but this requires me to make individual if statements for all of the types I want to support. I'd like to have it so that I can support any arbitrary type using some kind of template. I've created some test code that sort of works, but there are issues:
class Test {
std::type_index type;
void *value;
public:
template <typename T>
Test(T val) : type(typeid(val)) {
T *val_p = new T;
*val_p = val;
value = (void *)val;
}
Test() : type(typeid(void)) {
value = nullptr;
}
~Test() {
//no idea how I could make this work
}
template <typename T>
T get() {
if (std::type_index(typeid(T)) == type) {
T *val_p = (T *)value;
return *val_p;
} else {
throw std::bad_typeid();
}
}
};
What I have so far works, but I don't think it would be possible to implement a destructor or copy/move constructors. The whole point is I want to store this all in a single std::unordered_map, so I can't (AFAIK) just make a template class and go from there. So, is it possible to do what I'm trying to do, and if so, how would I do it?
Based on the suggestion of GManNickG, I'm going with boost::any, as it most closely resembles what I'm looking for.
I haven't yet implemented it into the code, but the basic structure will be something along the lines of:
#include <typeinfo>
#include <boost/any.hpp>
class Statistic {
boost::any value;
public:
template <typename T>
Statistic(T val) : value(val) {}
Statistic() : value() {}
template <typename T>
bool checkType() {
return typeid(T) == value.type();
}
//Will cause an exception if the type doesn't match
//Caller should check type if unsure
template <typename T>
T get() {
if (checkType<T>()) {
return boost::any_cast<T>(value);
} else {
//throw some exception
throw bad_any_cast();
}
}
}
With this, I don't need to deal with destructors or copy/move functions, since the implicit ones will call the code already implemented by the boost library.
EDIT:
Thanks to milleniumbug for pointing out boost::any already stores the std::type_info
I'm using something like:
struct VectorCache
{
template<typename T>
std::vector<T>& GetTs()
{
static std::vector<T> ts;
return ts;
}
};
to create/access some vectors based on the contained type. This works fine as long as I have only one object of type VectorCache, but when I use multiple objects I will get same vectors from all instances of VectorCache as the vectors are static variables.
I tried to move the vectors as member variables using something similar to boost::any and access them using std::type_index of T, but this is somehow slower than the direct access I used before.
Another options is to transform struct VectorCache to something like template<int index> struct VectorCache, but the problem is still there - I will have to be careful to have only one instance/index to have correct behaviour.
Is it possible to access the vectors directly based on T and also have the caching instance based instead of class based?
You could try an unchecked analogue of Boost.Any. See if that's fast enough for you (though I don't believe it would make a big difference):
#include <memory>
#include <type_traits>
#include <typeindex>
#include <unordered_map>
#include <vector>
class AnyCache
{
struct TEBase
{
virtual ~TEBase() {}
virtual void * get() = 0;
};
template <typename T> struct TEObject : TEBase
{
T obj;
virtual void * get() override { return static_cast<void *>(&obj); }
};
std::unordered_map<std::type_index, std::unique_ptr<TEBase>> cache;
public:
AnyCache(AnyCache const &) = delete;
AnyCache & Operator=(AnyCache const &) = delete;
template <typename T> decltype(auto) get()
{
using U = std::decay_t<T>;
using C = std::vector<U>;
std::unique_ptr<TEBase> & p = cache[typeid(U)];
if (!p) { p = std::make_unique<TEObject<C>>(); }
return *static_cast<C *>(p->get());
}
};
Usage:
AnyCache ac;
ac.get<int>().push_back(20);
ac.get<std::string>().push_back("Hello");
for (auto const & x : ac.get<Foo>()) { std::cout << x << '\n'; }
If - and it's a big if - your VectorCache-using code isn't threaded, you can do this:
struct VectorCache
{
VectorCache() : instance_counter_(++s_instance_counter_) { }
template<typename T>
std::vector<T>& GetTs()
{
static std::vector<std::vector<T>> tss;
if (tss.size() <= instance_counter_)
tss.resize(instance_counter_);
return tss[instance_counter_];
}
size_t instance_counter_;
static size_t s_instance_counter_;
};
// and define size_t VectorCache::s_instance_counter_;
implementation on ideone.com
With a little synchronisation you can make it thread safe, or even thread specific if that suits. Add deletion of copy construction / assignment etc. if that makes sense in your intended usage.
Using C++, I'm trying to create a generic container class to handle multiple data types. It's a common problem with a variety of solutions, but I've found nothing as... intuitive as I've grown accustomed to in languages like Python or even VB/VBA...
So here's my scenario:
I've built a DataContainer class based on boost::any which I use to store multiple data types of multiple elements. I use a map declared as:
std::map<std::string, DataContainer* (or DataContainerBase*)>
where DataContainer is a class that encapsulates an object of the type:
std::list<boost::any>
along with convenience functions for managing / accessing the list.
However, in the end, I'm still forced to do type conversions outside the data container.
For example, if I were to store a list of int values in the map, accessing them would require:
int value = boost::any_cast<int>(map["myValue"]->get());
I'd rather the boost code be contained entirely within the data container structure, so I would only need type:
int value = map["myValue"]->get();
or, worst-case:
int value = map["myValue"]->get<int>();
Of course, I could enumerate my data types and do something like:
int value = map["myValue"]->get( TYPE_INT );
or write type-specific get() functions:
getInt(), getString(), getBool() ...
The problem with the last two options is that they are somewhat inflexible, requiring me to declare explicitly each type I wish to store in the container. The any_cast solution (which I have implemented and works) I suppose is fine, it's just... inelegant? I dunno. It seems I shouldn't need to employ the internal mechanics externally as well.
As I see it, passing the value without declaring the value type in the call to the DataContainer member function would require a void* solution (which is undesirable for obvious reasons), and using a "get()" call would require (so far as I can tell) a "virtual template" member function defined at the base class level, which, of course, isn't allowed.
As it is, I have a workable solution, and really, my use in this case is limited enough in scope that most any solutions will work well. But I am wondering if perhaps there's a more flexible way to manage a generic, multi-type data container than this.
If you want to introduce some sugar for this:
int value = boost::any_cast<int>(map["myValue"]->get());
then you might want to make the get() function to return a proxy object, defined +- like this:
struct Proxy {
boost::any& value;
Proxy(boost::any& value) : value(value) {}
template<typename T>
operator T() {
return boost::any_cast<T>(value);
}
};
Then this syntax would work:
int value = map["myValue"]->get();
// returns a proxy which gets converted by any_cast<int>
However I recommend to keep things explicit and just use that syntax:
int value = map["myValue"]->get<int>();
Here get doesn't return a proxy object with a template method, but is a template method itself (but does the same as the template conversion operator shown above).
Today I have done some source code for the purpose you want. I know that this question is so old, but maybe this little piece of code is helpful for someone. It is mainly based on boost:any.
/*
* AnyValueMap.hpp
*
* Created on: Jun 3, 2013
* Author: alvaro
*/
#ifndef ANYVALUEMAP_HPP_
#define ANYVALUEMAP_HPP_
#include <map>
#include <boost/any.hpp>
using namespace std;
template <class T>
class AnyValueMap {
public:
AnyValueMap(){}
virtual ~AnyValueMap(){}
private:
map<T, boost::any> container_;
typedef typename map<T, boost::any>::iterator map_iterator;
typedef typename map<T, boost::any>::const_iterator map_const_iterator;
public:
bool containsKey(const T key) const
{
return container_.find(key) != container_.end();
}
bool remove(const T key)
{
map_iterator it = container_.find(key);
if(it != container_.end())
{
container_.erase(it);
return true;
}
return false;
}
template <class V>
V getValue(const T key, const V defaultValue) const
{
map_const_iterator it = container_.find(key);
if(it != container_.end())
{
return boost::any_cast<V>(it->second);
}
return defaultValue;
}
template <class V>
V getValue(const T key) const
{
return boost::any_cast<V>(container_.at(key));
}
template <class V>
void setValue(const T key, const V value)
{
container_[key] = value;
}
};
#endif /* ANYVALUEMAP_HPP_ */
A simple usage example:
AnyValueMap<unsigned long> myMap;
myMap.setValue<double>(365, 1254.33);
myMap.setValue<int>(366, 55);
double storedDoubleValue = myMap.getValue<double>(365);
int storedIntValue = myMap.getValue<int>(366);
There is some class which have methods like:
int getSomething1();
std::string getSomething2();
someClass getSomething3();
There is structure which describes fields of this class like:
{"name of field", pointer to getter, std::type_info}
Then I would like to use it as follows:
if(type == int){
field_int = (int)getter();
}
else if(type == std::string){
field_string = (std::string)getter();
}
etc.
How to transform getters like
int getSomething1();
std::string getSomething2();
etc.
to some universal function pointer and then to get the correct value of field?
This answer of mine to another question addresses your problem pretty well. With some minor modifications, you get this:
template<class C, class T>
T get_attribute(const C& instance, T (C::*func)() const) {
return (instance.*func)();
}
Assuming the following:
struct Foo {
int getSomething1() const;
std::string getSomething2() const;
someClass getSomething3() const;
};
You can use it like this:
Foo foo;
int value = get_attribute<Foo, int>(foo, &Foo::getSomething1);
std::string value = get_attribute<Foo, std::string>(foo, &Foo::getSomething2);
someClass value = get_attribute<Foo, someClass>(foo, &Foo::getSomething3);
You can of course transform get_attribute to a functor to bind some or all of the arguments.
There is no formal universal function pointer, the equivalent of void*
for data. The usual solution is to use void (*)(); you are guaranteed
that you can convert any (non-member) function pointer to this (or any
other function pointer type) and back without loss of information.
If there is a certain similarity in the function signatures (e.g. all
are getters, with no arguments) and how they are used, it may be
possible to handle this with an abstract base class and a set of derived
classes (possibly templated); putting pointers to instances of these
classes in a map would definitely be more elegant than an enormous
switch.
What you are trying to achieve can be better achieved with already existing containers such as a boost fusion sequence. I'd advice that you try this first.
Templates to the rescue!
// Create mapping of type to specific function
template <typename T> T getSomething(); // No default implementation
template <> int getSomething<int>() { return getSomething1(); }
template <> std::string getSomething<std::string>() { return getSomething2(); }
template <> someClass getSomething<someClass>() { return getSomething3(); }
// Convenience wrapper
template <typename T> void getSomething(T& t) { t = getSomething<T>(); }
// Use
int i = getSomething<int>();
std::string s;
getSomething(s);
As I understand, your difficulty is in storing the function pointers, since they are of different types. You can solve this using Boost.Any and Boost.Function.
#include <boost/any.hpp>
#include <boost/function.hpp>
int getInt() {
return 0;
}
std::string getString() {
return "hello";
}
int main()
{
boost::function<boost::any ()> intFunc(getInt);
boost::function<boost::any ()> strFunc(getString);
int i = boost::any_cast<int>(intFunc());
std::string str = boost::any_cast<std::string>(strFunc());
}