std::map
のキーを、std::set
(またはstd::vector
)の要素を使用して設定したいとします。マップからセットを初期化する方法
次のようなもの...これは明示的にセットを反復処理することなく、
std::set<int> keys = { 3,4,6 };
std::map<int,string> results(keys); // syntax error
を行うことができますか?
std::map
のキーを、std::set
(またはstd::vector
)の要素を使用して設定したいとします。マップからセットを初期化する方法
次のようなもの...これは明示的にセットを反復処理することなく、
std::set<int> keys = { 3,4,6 };
std::map<int,string> results(keys); // syntax error
を行うことができますか?
できません。 map
はset
ではありません。基本的な構造が類似していても、基本的に異なるコンテナです。
つまり、何でも可能です。 std::map
の範囲コンストラクタは、範囲の要素が既にソートされている場合は線形時間であり、set
が保証します。つまり、すべての要素にトランスを適用して新しい範囲を作成するだけです。
template <class V, class K>
std::map<K, V> as_map_default(std::set<K> const& s) {
auto f = [](K const& k) { return std::make_pair(k, V{}); }
return std::map<K,V>(
boost::make_transform_iterator(s.begin(), f),
boost::make_transform_iterator(s.end(), f));
}
std::map<int,string> results = as_map_default<string>(keys);
誰かが「もっとも簡単な解決策はXである」と言い、Xには「クラスV」を定義する行が含まれるたびに、誰かがC++を覚えていないと宣誓します。 :-)注:私は答えが好きですが、男、非常に多くの山括弧。 – ShadowRanger
答えは "できません"と言うことから始まり、次にそれを行う方法を示すために進みます。その反復は、基本的に私が見たいと思っていたマップコンストラクタの中に隠されています。これは最初の2つの単語を除いて正解です。 :) – nobar
は、これが指定できます。最も簡単なだけで
boost::make_transform_iterator
のようなものを使用する(または独自のロール)するために、次のようになりますし、あなたが常にデフォルトの初期化をしたいかどうtemplate <class K, class F class V = decltype(std::declval<F&>()(std::declval<K const&>()))::second_type> std::map<K, V> as_map(std::set<K> const& s, F&& f) { return std::map<K,V>( boost::make_transform_iterator(s.begin(), f), boost::make_transform_iterator(s.end(), f)); } std::map<int,string> results = as_map(keys, [](int i){ return std::make_pair(i, std::string{}); });
を、単に減らすことができます明示的に反復することなく行われますか?
いいえ反復せずにセット内のキーを知る方法はありません。あたかも暗黙の変換があるかのように、がと表示されるような関数を書くことができますが、それらの関数は最終的にソースコレクションを反復しなければなりません。次のように
簡単な方法は次のとおりです。もちろん
#include <set>
#include <map>
#include <string>
auto build_map(const std::set<int>& source) -> std::map<int,std::string>
{
std::map<int,std::string> results;
for (auto const& i : source) {
results[i];
}
return results;
}
int main()
{
std::set<int> keys = { 3,4,6 };
auto results = build_map(keys);
}
それが可読性改善されるかどうか、我々はtemplatiseことがあります。
#include <set>
#include <vector>
#include <unordered_set>
#include <map>
#include <string>
#include <utility>
template<class MappedType, class SourceContainer>
auto build_map(SourceContainer&& source)
{
using source_type = std::decay_t<SourceContainer>;
using key_type = typename source_type::value_type;
std::map<key_type , MappedType> results;
for (auto const& i : source) {
results[i];
}
return results;
}
int main()
{
std::set<int> keys = { 3,4,6 };
auto results = build_map<std::string>(keys);
// also
results = build_map<std::string>(std::vector<int>{3, 4, 6});
results = build_map<std::string>(std::unordered_set<int>{3, 4, 6});
}
反復ベースの初期化を非常に簡単に行う方法の良い例です。 – nobar
1)あなたがしたい任意の特定の理由はありますか? 2)値の文字列をどのようにしたいですか? – Beta
これが可能なら、私は非常に驚いています。なぜなら、そのステートメントから生じる初期化されていない値にアクセスすることは許容されるべきではないからです。 – ApproachingDarknessFish
@Beta:1)キーを簡潔に(値に関係なく)指定できるAPIを作成します。 2)値をデフォルトに初期化します。 – nobar