STL 文字列を操作する結合関数があります。次のようなコンテナに適用できるようにしたい:
getFoos(const std::multimap<std::string, std::string>& map) {
return join_values(",", map.equal_range("foo"));
つまり、コレクション内の一致するすべてのキーを検索し、指定されたセパレーターを使用して値を 1 つの文字列に連結します。キーの範囲、コンテナの内容全体などについても同じ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
の任意の組み合わせが機能するようです。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
関数とjoin_keys
ファンクターをリファクタリングして、ほとんどのコードが重複しないようにするにはどうすればよいですか?
に基づく少し単純な解決策を見つけましたstd::accumulate
が、範囲内の各要素に対して文字列全体の 2 つの完全なコピー操作が必要なようです。
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>(","));