Tim*_*ter 3 c++ string containers stl join
我有一个操作STL字符串的连接函数.我希望能够将它应用于这样的容器:
getFoos(const std::multimap<std::string, std::string>& map) {
return join_values(",", map.equal_range("foo"));
Run Code Online (Sandbox Code Playgroud)
换句话说,查找集合中的所有匹配键,并将值与给定的分隔符连接成一个字符串.用同样的事情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));
}
Run Code Online (Sandbox Code Playgroud)
(我意识到继承std::string或者任何键/值类型通常被认为是一个坏主意,但我没有重载或覆盖任何函数,我不需要虚拟析构函数.我只是这样做我可以直接使用结果而for_each无需定义隐式转换运算符.)
有非常相似的定义join_range_keys,使用first_type和p.first代替second_type和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"));
Run Code Online (Sandbox Code Playgroud)
这给我留下了几个问题:
join_values自动推导出模板参数类型,这样我join_values<MapType>每次都不需要调用它?join_values和join_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>(","));
Run Code Online (Sandbox Code Playgroud)
STL算法通常使用迭代器而不是容器,所以我建议如下所示.
template <typename T, typename Iterator>
T join(
const T sep,
Iterator b,
Iterator e)
{
T t;
while (b != e)
t = t + *b++ + sep;
return t;
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要一个将拉出键或值的迭代器.这是一个例子:
template <typename Key, typename Iterator>
struct KeyIterator
{
KeyIterator(
Iterator i)
:_i(i)
{
}
KeyIterator operator++()
{
++_i;
return *this;
}
bool operator==(
KeyIterator ki)
{
return _i = ki._i;
}
typename Iterator::value_type operator*()
{
return _i->first;
}
};
Run Code Online (Sandbox Code Playgroud)
如何使用:
string s = join(",", KeyIterator(my_map.begin()), KeyIterator(my_map.end()));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2801 次 |
| 最近记录: |