Is this the correct, most sane way to do variadic templates in C++?
All that this function does is to see if gate has a key, if it has, it adds it to a vector of values, if not, it default constructs an object in place.
This function belongs to a templated class called core_table
where K
is the key type and V
the value type.
template <typename ...Args>
std::vector<V> values_at(Args const & ...args) const {
std::initializer_list<K> input {args...};
std::vector<V> output;
output.reserve(input.size());
for (auto const & e : input) {
auto const it = gate.find(e);
if (it != gate.end()) {
output.emplace_back((*it)->second);
continue;
}
output.emplace_back();
}
return output;
}
I'm asking it because all the examples of variadic templates that I saw until now made use of recursion. I'm still in a state of desbelief that I can just write std::initializer_list<K> input {k, args...};
and iterate over it, I literally didn't knew until now that this was possible - this does make variadic templates much more approachable in C++, at least for me.
So, is this a good example? How can I make it better, more optimized?
Working Example
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <vector>
using std::cout;
using std::endl;
template <typename K, typename V>
class core_table {
using value = std::pair<K, V>;
using chain = std::list<value>;
using iterator = typename chain::iterator;
using const_iterator = typename chain::const_iterator;
struct compare {
using is_transparent = void;
bool operator ()(const_iterator x, const_iterator y) const {
return x->first < y->first;
}
bool operator ()(const_iterator x, K const & k) const {
return x->first < k;
}
bool operator ()(K const & k, const_iterator y) const {
return k < y->first;
}
};
chain data;
std::set<iterator, compare> gate;
public:
core_table() = default;
core_table(core_table && ct) = default;
core_table(core_table const & ct) {
for (auto const & e : ct) {
push(e.first, e.second);
}
}
core_table(std::initializer_list<value> il) {
for (auto const & e : il) {
push(e.first, e.second);
}
}
template <typename Key, typename Value>
core_table & insert(const_iterator cit, Key && k, Value && v) {
auto const it = gate.find(k);
if (it != gate.end()) {
(*it)->second = std::forward<Value>(v);
return *this;
}
gate.emplace(data.emplace(cit, std::forward<Key>(k), std::forward<Value>(v)));
return *this;
}
template <typename Key, typename Value>
core_table & push(Key && k, Value && v) {
return insert(data.end(), std::forward<Key>(k), std::forward<Value>(v));
}
template <typename ...Args>
std::vector<V> values_at(Args const & ...args) const {
std::initializer_list<K> input {args...};
std::vector<V> output;
output.reserve(input.size());
for (auto const & e : input) {
auto const it = gate.find(e);
if (it != gate.end()) {
output.emplace_back((*it)->second);
continue;
}
output.emplace_back();
}
return output;
}
};
int main() {
core_table<std::string, std::string> ct {{"a", "hello"}, {"b", "world"}};
for (auto const & e : ct.values_at("b", "a")) {
cout << e << endl;
}
return 0;
}
#include <vector>
- are you missing declarations ofV
andK
from somewhere else in your code? It's better if you can provide a [mcve], so that we can compile it and suggest changes that are at least superficially correct. \$\endgroup\$ – Toby Speight Feb 6 '17 at 14:13