Мне нравится строить "карту", используя std::tuple
, ключ std::string
, значение любого типа, оно определяется следующим образом:
template<typename... Args>
using Map = std::tuple<std::pair<std::string, Args>...>;
И у меня есть функция MakeMap
, который принимает переменные аргументы, чтобы превратить аргументы в Map
и вернуть его:
template<typename... Args>
Map<???> MakeMap(Args&&... args) {
???
}
И я бы хотел, чтобы аргументы MakeMap
были в формате std::string, type1, std::string, type2, ...
(ключс последующим значением), например:
auto map = MakeMap("key1", 42, "key2", "hello world"); // OK
auto map = MakeMap(1, 2); // expects compiling error
auto map = MakeMap("key1", 42, "key2"); // expects compiling error
Итак, как реализовать функцию MakeMap
(в C ++ 11), чтобы заставить работать вышеуказанный синтаксис вызова?
Спасибо.
РЕДАКТИРОВАТЬ
Наконец-то я понял это с помощью @ Kostas, спасибо!
- Сначала спариваем аргументы:
template<typename... Args>
struct MapType;
template<>
struct MapType<> {
using type = typename std::tuple<>;
};
template<typename K, typename V, typename... Args>
struct MapType<K, V, Args...> {
using type = std::tuple<std::pair<std::string, V>, typename MapType<Args...>::type>;
};
Теперь мы получаем вложенное
std::tuple
, нам нужно его сгладить (следующий фрагмент кода вдохновлен
этим ответом , благодаря оригинальному автору):
template<typename T, typename U>
struct FlattenHelper;
template<typename... Args, typename... Heads, typename... Tails>
struct FlattenHelper<std::tuple<Args...>, std::tuple<std::tuple<Heads...>, Tails...>> {
using type = typename FlattenHelper<std::tuple<Args...>, std::tuple<Heads..., Tails...>>::type;
};
template<typename... Args, typename Head, typename... Tails>
struct FlattenHelper<std::tuple<Args...>, std::tuple<Head, Tails...>> {
using type = typename FlattenHelper<std::tuple<Args..., Head>, std::tuple<Tails...>>::type;
};
template<typename... Args>
struct FlattenHelper<std::tuple<Args...>, std::tuple<>> {
using type = std::tuple<Args...>;
};
template<typename T>
struct Flatten;
template<typename... Args>
struct Flatten<std::tuple<Args...>> {
using type = typename FlattenHelper<std::tuple<>, std::tuple<Args...>>::type;
};
Теперь мы можем определить
MakeMap
следующим образом:
template<typename... Args>
using ReturnType = typename Flatten<typename MapType<Args...>::type>::type;
template<typename K, typename V, typename... Args>
ReturnType<K, V, Args...> MakeMap(K&& k, V&& v, Args&&... args) {
// `std::forward` is omitted here
return std::tuple_cat(std::make_tuple(std::make_pair(k, v)), MakeMap(args...));
}
std::tuple<> MakeMap() {
return std::tuple<>();
}