Nie da się tak prosto dynamicznie ustalać typu kontenera. Musisz wykorzystać specjalizację szablonów, inaczej kompilator będzie próbował skompilować kod, który nie ma prawa działać.
template<typename>
struct Inserter;
template<typename T>
struct InserterBase
{
using container_type = T;
InserterBase(container_type& c) : c(c) {}
container_type& c;
};
template<typename T, typename Comp>
struct Inserter<std::set<T, Comp>> : InserterBase<std::set<T, Comp>>
{
using InserterBase<std::set<T, Comp>>::InserterBase;
void operator()(typename Inserter::container_type::value_type const& v) const {
this->c.insert(v);
}
};
template<typename T, typename V, typename Comp>
struct Inserter<std::map<T, V, Comp>> : InserterBase<std::map<T, V, Comp>>
{
using InserterBase<std::map<T, V, Comp>>::InserterBase;
void operator()(typename Inserter::container_type::value_type const& v) const {
this->c.insert(v);
}
};
template<typename T, typename Comp>
struct Inserter<std::vector<T, Comp>> : InserterBase<std::vector<T, Comp>>
{
using InserterBase<std::vector<T, Comp>>::InserterBase;
void operator()(typename Inserter::container_type::value_type const& v) const {
this->c.push_back(v);
}
};
template<typename T>
auto make_inserter(T& t){
return Inserter<T>(t);
}
I wykorzystanie:
auto main() -> int
{
vector<int> vi = {1,2,3};
set<double> sd = {4,5,6};
map<int, string> mis = {{42, "answer"}};
auto vi_inserter = make_inserter(vi);
auto sd_inserter = make_inserter(sd);
auto mis_inserter = make_inserter(mis);
vi_inserter(10);
sd_inserter(5);
sd_inserter(7);
mis_inserter({69, "position"});
DBG_CONT(vi);
DBG_CONT(sd);
for(auto const& p : mis){
cout << "K: " << p.first << "\t V:" << p.second << endl;
}
}
http://melpon.org/wandbox/permlink/2XUfgpi0F2Uv4Mgi
Ale coś mi się wydaje, że z tag dispatch można to ładniej zrobić.
============================================
Edit: tak, można:
struct unknown_type_please_specialize_trait{};
struct needs_insert{};
struct needs_push_back{};
template<typename T>
struct inserter_type { using type = unknown_type_please_specialize_trait; };
template<typename T, typename Comp, typename Alloc>
struct inserter_type<std::set<T, Comp, Alloc>> { using type = needs_insert; };
template<typename K, typename V, typename Comp, typename Alloc>
struct inserter_type<std::map<K, V, Comp, Alloc>> { using type = needs_insert; };
template<typename T, typename Alloc>
struct inserter_type<std::vector<T, Alloc>> { using type = needs_push_back; };
template<typename C, typename VT>
void my_insert(needs_insert, C& c, VT&& v){
c.insert(std::forward<VT>(v));
}
template<typename C, typename VT>
void my_insert(needs_push_back, C& c, VT&& v){
c.push_back(std::forward<VT>(v));
}
template<typename C>
void my_insert(C& c, typename decay_t<C>::value_type v){
using tag = typename inserter_type<std::decay_t<C>>::type;
my_insert(tag{}, c, std::move(v));
}
i main jest prostszy (ale insertera też se możesz zrobić oczywiście):
auto main() -> int
{
vector<int> vi = {1,2,3};
set<double> sd = {4,5,6};
map<int, string> mis = {{42, "answer"}};
my_insert(vi, 10);
my_insert(sd, 5);
my_insert(sd, 7);
my_insert(mis, {69, "position"});
DBG_CONT(vi);
DBG_CONT(sd);
for(auto const& p : mis){
cout << "K: " << p.first << "\t V: " << p.second << endl;
}
}
http://melpon.org/wandbox/permlink/ZOhaq2NydzPjJIXG