次のスニペットをgcc4.7でコンパイルしてみました
vector<pair<int,char> > vp = {{1,'a'},{2,'b'}};
//For pair vector, it works like a charm.
vector<Tuple<int,double,char> > vt = {{1,0.1,'a'},{2,4.2,'b'}};
ただし、タプルのベクトルの場合、コンパイラーは文句を言います。
エラー:初期化リストから「std :: Tuple」に変換すると、明示的なコンストラクター「constexpr std :: Tuple <> :: Tuple(_UElements && ...)[with _UElements = {int、double、char}; = void; _Elements = {int、double、char}]」
コンパイラーがこぼしたエラー情報は、私にはまったく意味不明です。タプルのコンストラクターがどのように実装されたかはわかりませんが、均一な初期化で完全に問題ないことはわかっています(例:Tuple<int,float,char>{1,2.2,'X'}
)したがって、私が遭遇した問題はコンパイラのTODOだけなのか、それともC++ 11標準で定義されたものなのかと思います。
関連するstd::Tuple
コンストラクタはexplicit
です。これは、使用したい構文がコピーの初期化(explicit
コンストラクターの呼び出しを禁止する)に関して定義されているため、実行したいことは不可能であることを意味します。対照的に、 std::Tuple<int, float, char> { 1, 2.2, 'X' }
は直接初期化を使用します。 std::pair
にはexplicit
以外のコンストラクタのみがあります。
直接初期化または標準タプルファクトリ関数のいずれかを使用します(例:std::make_Tuple
)。
これは実際には、c ++ 11機能で実行可能です。
はい、initializer_listは、そのすべての要素が同じ型であることを望んでいます。コツは、必要なすべての型に対してstatic_cast
になることができるラッパークラスを作成できることです。これは簡単に実現できます。
template <typename... tlist>
class MultiTypeWrapper {
};
template <typename H>
class MultiTypeWrapper<H> {
public:
MultiTypeWrapper() {}
MultiTypeWrapper(const H &value) : value_(value) {}
operator H () const {
return value_;
}
private:
H value_;
};
template <typename H, typename... T>
class MultiTypeWrapper<H, T...>
: public MultiTypeWrapper<T...> {
public:
MultiTypeWrapper() {}
MultiTypeWrapper(const H &value) : value_(value) {}
// If the current constructor does not match the type, pass to its ancestor.
template <typename C>
MultiTypeWrapper(const C &value) : MultiTypeWrapper<T...>(value) {}
operator H () const {
return value_;
}
private:
H value_;
};
暗黙的な変換コンストラクターを使用して、{1,2.5、 'c'、4}のようなものをMultiTypeWrapperタイプのinitializer_list(または暗黙的に初期化子リストを変換するベクトル)に渡すことができます。つまり、このようなintializer_listを引数として受け入れる以下のような関数を書くことはできません。
template <typename... T>
std::Tuple<T...> create_Tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
....
}
別のトリックを使用して、ベクトルの各値を元の型にキャストし(MultiTypeWrapper
の定義で暗黙の変換を提供することに注意)、それをタプルの対応するスロットに割り当てます。これはテンプレート引数の再帰のようなものです:
template <int ind, typename... T>
class helper {
public:
static void set_Tuple(std::Tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
std::get<ind>(t) = static_cast<typename std::Tuple_element<ind,std::Tuple<T...> >::type>(v[ind]);
helper<(ind-1),T...>::set_Tuple(t,v);
}
};
template <typename... T>
class helper<0, T...> {
public:
static void set_Tuple(std::Tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
std::get<0>(t) = static_cast<typename std::Tuple_element<0,std::Tuple<T...> >::type>(v[0]);
}
};
template <typename... T>
std::Tuple<T...> create_Tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
std::Tuple<T...> res;
helper<sizeof...(T)-1, T...>::set_Tuple(res, init);
return res;
}
C++は関数の特殊化をサポートしていないため、set_Tuple
のヘルパークラスを作成する必要があることに注意してください。コードをテストしたい場合:
auto t = create_Tuple<int,double,std::string>({1,2.5,std::string("ABC")});
printf("%d %.2lf %s\n", std::get<0>(t), std::get<1>(t), std::get<2>(t).c_str());
出力は次のようになります。
1 2.50 ABC
これはclang 3.2を搭載した私のデスクトップでテストされています
私の入力が役に立てば幸い:)