【发布时间】:2020-02-20 07:51:35
【问题描述】:
我喜欢用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,我们需要将其展平(以下代码sn-p 的灵感来自this answer,感谢原作者):
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<>();
}
【问题讨论】:
-
我很好奇是什么让你想要创造这样的东西?
-
@Kosta 我们正在构建一个无模式的 RPC 框架,并且可能与 Lua 和 JavaScript 等其他动态语言进行通信,因此我们必须在 Lua 中模拟表,在 Javascript 中模拟对象,不能简单地使用JSON 由于一些历史原因。
标签: c++ c++11 variadic-templates variadic-functions template-meta-programming