如何实现地图和集合通用的模板?
Posted
技术标签:
【中文标题】如何实现地图和集合通用的模板?【英文标题】:How to implement a template common for maps and sets? 【发布时间】:2020-12-22 19:29:47 【问题描述】:我正在从数据库中加载各种数据,并且已经实现了一个模板方法:
template <typename R>
bool
loadMap(map<const string, R> &store, const char *query)
...
for (auto row : rows(query))
store.insert(make_pair(row[0], R(row[1], row[2], ....));
该方法将query
发送到数据库服务器并使用结果填充store
。第一列成为映射的键,其余字段形成值结构。这行得通。
但是,在某些情况下,查询仅返回 一个 列——存储在 set
(或 unordered_set
)中——没有任何关联的值。
目前这些情况是由它们自己的方法处理的,我想将我的 loadMap
-function 扩展到这些其他类型的容器——也许,将其重命名为 loadContainer
。
这个新的loadContainer
的声明看起来如何,以及它如何仅使用键调用store.insert()
,没有值?
(我知道将集合转换为所有值都为空的地图的躲闪,但我想避免这种情况。)
实际上,我什至想不出处理map
和unordered_map
的方法——虽然insert
完全一样,但我该如何声明这样的函数?这两种地图类型似乎没有共同的祖先(也没有“接口”,使用 Java 术语)...
【问题讨论】:
你可以使用map<const string, std::optional<R>>
我正要发表评论,但被打败了。使用std::optional<R>
。
谢谢你们,但它仍然是map
,不是吗?不是set
——甚至不是unordered_map
...
在我的工作中(使用 Java),我们遇到了这个问题,最终得到了一个核心 template<Container> void queryAll(Container<T>&)
来完成真正的工作,然后是三个辅助包装器:List<T> queryAll()
、T queryOneOrThrow()
和Optional<T> queryOneOrNone()
重载。
@MooingDuck,Java 有运行时类型信息 (RTTI)!您可以在运行时动态创建新的类,然后根据返回的列的名称/类型为每个 SQL 查询创建这些新创建类型的对象。但是,在 C++ 中没有这种(昂贵的)奢侈品……
【参考方案1】:
你可能有重载
template <typename R>
bool loadContainer(std::map<string, R> &store, const char *query)
// ...
for (auto row : rows(query))
store.insert(std::make_pair(row[0], R(row[1], row[2] /*, ...*/));
// ...
bool loadContainer(std::set<string> &store, const char *query)
// ...
for (auto row : rows(query))
store.insert(row[0]);
// ...
或者,为了避免过载,您可以这样做 (C++17)
template <typename Container>
bool loadContainer(Container& store, const char *query)
// ...
for (auto row : rows(query))
if constexpr (is_map<Container>::value)
using R = typename Container::mapped_type;
store.insert(std::make_pair(row[0], R(row[1], row[2] /*, ...*/));
else
store.insert(row[0]);
// ...
具有适当的特征,例如
template <typename T, typename Enabler = void>
struct is_map : std::false_type ;
template <typename T>
struct is_map<T, std::void_t<typename T::mapped_type>> : std::true_type ;
【讨论】:
我希望rows()
调用真的很简单 :) 但是,也许,我应该把它变成一个自己的迭代器...... Khm......不管怎样,@ 987654326@ 与 unordered_map
?这两种类型是否真的也需要单独的方法——即使代码相同?
您可能仍然使用 SFINAE 或 c++20 概念。
不,它必须使用 g++-4.4 与 -std=gnu++0x
一起工作
SFINAE 甚至可以在 C++11 之前使用,但我们通常必须重写 C++11 后 std 中提供的一些实用程序。
@MikhailT。 不,它必须使用 g++-4.4 与 -std=gnu++0x 一起使用 -- boost 可能是你的朋友。【参考方案2】:
解决了distinguishing between maps and sets 的问题后,我能够为不同的容器类型实现不同的insert
函数。
我的loadMap
模板化函数只是调用insert(store, key, value)
-- 并且在编译时根据store
的类型选择正确的insert
实现。 (对于集合,value
将被忽略。)
【讨论】:
以上是关于如何实现地图和集合通用的模板?的主要内容,如果未能解决你的问题,请参考以下文章