我有一个对 STL 字符串进行操作的连接函数。我希望能够将它应用于这样的容器:
getFoos(const std::multimap<std::string, std::string>& map) {
return join_values(",", map.equal_range("foo"));
换句话说,在集合中找到所有匹配的键,并将这些值连接成具有给定分隔符的单个字符串。对于一系列键,/对于容器的全部内容等,lower_bound()
同样的事情。upper_bound()
begin()
end()
我能得到的最接近的是以下内容:
template <typename T>
struct join_range_values : public T::const_iterator::value_type::second_type {
typedef typename T::const_iterator::value_type pair_type;
typedef typename pair_type::second_type value_type;
join_range_values(const value_type& sep) : sep(sep) { }
void operator()(const pair_type& p) {
// this function is actually more complex...
*this += sep;
*this += p.second;
}
private:
const value_type sep;
};
template <typename T>
typename T::const_iterator::value_type::second_type join_values(
const typename T::const_iterator::value_type::second_type& sep,
const std::pair<typename T::const_iterator, typename T::const_iterator>& range) {
return std::for_each(range.first, range.second, join_range_values<T>(sep));
}
(我意识到继承std::string
或任何键/值类型通常被认为是一个坏主意,但我没有重载或覆盖任何函数,也不需要虚拟析构函数。我这样做只是为了我可以直接使用的结果,for_each
而不必定义隐式转换运算符。)
对于join_range_keys
, 使用first_type
和p.first
代替second_type
and有非常相似的定义p.second
。我假设类似的定义适用于加入std::set
和std::multiset
密钥,但我没有任何需要。
我可以将这些函数应用于具有各种类型字符串的容器。键和值类型的任何组合和map
组合似乎都有效:multimap
string
wstring
typedef std::multimap<std::string, std::string> NNMap;
const NNMap col;
const std::string a = join_keys<NNMap>(",", col.equal_range("foo"));
const std::string b = join_values<NNMap>(",", col.equal_range("foo"));
typedef std::multimap<std::string, std::wstring> NWMap;
const NWMap wcol;
const std::string c = join_keys<NWMap>(",", wcol.equal_range("foo"));
const std::wstring d = join_values<NWMap>(L",", wcol.equal_range("foo"));
typedef std::multimap<std::wstring, std::wstring> WWMap;
const WWMap wwcol;
const std::wstring e = join_keys<WWMap>(L",", wwcol.equal_range(L"foo"));
const std::wstring f = join_values<WWMap>(L",", wwcol.equal_range(L"foo"));
这给我留下了几个问题:
- 我错过了一些更简单的方法来完成同样的事情吗?函数签名尤其显得过于复杂。
- 有没有办法
join_values
自动推断模板参数类型,这样我就不需要join_values<MapType>
每次都调用它? - 如何重构
join_values
andjoin_keys
函数和仿函数以避免重复大部分代码?
我确实找到了一个稍微简单的解决方案std::accumulate
,但它似乎需要对范围内的每个元素对整个字符串进行两次完整的复制操作,所以据我所知,它的效率要低得多。
template <typename T>
struct join_value_range_accum : public T::const_iterator::value_type::second_type
{
typedef typename T::const_iterator::value_type::second_type value_type;
join_value_range_accum(const value_type& sep) : sep(sep) {}
using value_type::operator=;
value_type operator+(const typename T::const_iterator::value_type& p)
{
return *this + sep + p.second;
}
private:
const value_type sep;
};
typedef std::multimap<std::string, std::string> Map;
Map::_Pairii range = map.equal_range("foo");
std::accumulate(range.first, range.second, join_value_range_accum<Map>(","));