Reputation: 193
So i've got a bunch of shared_ptr's as private members of a class called 'Handler' each pointing to a different template Cache classes. Like so:
shared_ptr< Cache<T1> > t1Cache;
shared_ptr< Cache<T2> > t2Cache;
shared_ptr< Cache<T3> > t3Cache;
Each Cache class simply holds a map with a string as a key and T as the item and functions to get/update and add an item to the map. I want to have a single member function in 'Handler' for an update,add and get operations. So I could call for example: ( Where ITEM_TYPE is an enum )
Handler handler;
auto something = handler.getItem( key1, TYPE_T1 );
handler.addItem( key2, TYPE_T2, newItem );
handler.updateItem( key3, TYPE_T3, newValue);
I tried at first just having a switch based on the enum like so:
template <typename T>
auto addItem( const std::string& key, ITEM_TYPE type, T nItem )
{
switch( type )
{
case TYPE_T1:
t1Cache->addItem( key, nItem );
break;
case TYPE_T2:
t2Cache->addItem( key ,nItem );
break;
}
}
Unfortunately I have a basic knowledge of templates so I didn't realize that that will not work. At the moment as a temporary solution im just using a different function for each type, though i'd really like to consolidate it all into one. I thought that maybe 'constexpr if' will help but it's not supported, is this even possible?
EDIT: Sorry the title isn't really worded right, was not sure how to title this
Upvotes: 1
Views: 132
Reputation: 12485
What about something like this?
#include <string>
#include <tuple>
template <class T> class Cache
{
public:
void addItem(std::string const& key, T item)
{
}
};
template <class... T> class SuperCache
{
public:
template <class U> void addItem(std::string const& key, U&& item)
{
std::get<Cache<std::decay_t<U>>>(caches_).addItem(key, std::forward<U>(item));
}
private:
std::tuple<Cache<T>...> caches_;
};
int main()
{
SuperCache<int, double> cache;
cache.addItem("a", 5);
cache.addItem("b", 5.0);
}
If you can use C++17, then here's another approach that might work (depending on your needs):
#include <string>
#include <unordered_map>
#include <variant>
template <class... T> class VariantCache
{
public:
template <class U> void addItem(std::string const& key, U&& item)
{
items_[key] = std::forward<U>(item);
}
private:
std::unordered_map<std::string, std::variant<T...>> items_;
};
int main()
{
VariantCache<int, double> cache;
cache.addItem("a", 5);
cache.addItem("b", 5.0);
}
Upvotes: 2
Reputation: 24946
I don't know why you would want to do this but you could encapsulate all caches into a tuple and use get<T>
within your function to select the proper tuple element:
#include <memory>
#include <tuple>
#include <vector>
#include <iostream>
template<class T> struct Cache
{
std::vector<T> x;
void add(T const& y) { x.push_back(y); }
};
template<class T1, class T2, class T3>
struct test
{
test() : _caches(std::make_tuple(std::make_shared<Cache<T1>>(),
std::make_shared<Cache<T2>>(), std::make_shared<Cache<T3>>())) {}
std::tuple<std::shared_ptr<Cache<T1>>, std::shared_ptr<Cache<T2>>,
std::shared_ptr<Cache<T3>>> _caches;
template<class T>
void add_item(T const& v)
{
std::get<std::shared_ptr<Cache<T>>>(_caches)->add(v);
}
};
int main()
{
test<int, float, double> a;
a.add_item(1);
std::cout << std::get<std::shared_ptr<Cache<int>>>(a._caches)->x.size() << "\n";
return 0;
}
Note that get<T>
does not compile if the tuple contains more than one item of type T
so this solution requires T1
, T2
and T3
to be distinct.
Upvotes: 1