从C STL关联容器连接键/值

我有一个操作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和p.second.我假设一个类似的定义将用于加入std :: set和std :: multiset键,但我没有任何需要.

我可以将这些函数应用于具有各种类型字符串的容器.任何组合的map和multimap以及键和值类型的字符串和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和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>(","));

解决方法:

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;
}

然后,您需要一个将拉出键或值的迭代器.这是一个例子:

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;
    }
};

如何使用:

string s = join(",", KeyIterator(my_map.begin()), KeyIterator(my_map.end()));
上一篇:安装ubuntu远程桌面xrdp可视化设置界面


下一篇:作为模板参数提供的allocator和作为C容器中的构造函数参数提供的allocator之间的区别?