以前の投稿のいくつかのアイデアを組み合わせて、ネストされた構造(GCC4.6でテスト済み)でも機能するソリューションを次に示します。
template <typename T, typename ...Args>
std::array<T, sizeof...(Args) + 1> make_array(T && t, Args &&... args)
{
static_assert(all_same<T, Args...>::value, "make_array() requires all arguments to be of the same type."); // edited in
return std::array<T, sizeof...(Args) + 1>{ std::forward<T>(t), std::forward<Args>(args)...};
}
奇妙なことに、戻り値を右辺値参照にすることはできません。ネストされた構造では機能しません。とにかく、ここにテストがあります:
auto q = make_array(make_array(make_array(std::string("Cat1"), std::string("Dog1")), make_array(std::string("Mouse1"), std::string("Rat1"))),
make_array(make_array(std::string("Cat2"), std::string("Dog2")), make_array(std::string("Mouse2"), std::string("Rat2"))),
make_array(make_array(std::string("Cat3"), std::string("Dog3")), make_array(std::string("Mouse3"), std::string("Rat3"))),
make_array(make_array(std::string("Cat4"), std::string("Dog4")), make_array(std::string("Mouse4"), std::string("Rat4")))
);
std::cout << q << std::endl;
// produces: [[[Cat1, Dog1], [Mouse1, Rat1]], [[Cat2, Dog2], [Mouse2, Rat2]], [[Cat3, Dog3], [Mouse3, Rat3]], [[Cat4, Dog4], [Mouse4, Rat4]]]
(最後の出力では、pretty-printerを使用しています。)
実際、この構造の型安全性を改善しましょう。すべてのタイプが同じであることは間違いありません。1つの方法は、上記で編集した静的アサーションを追加することです。もう1つの方法はmake_array
、次のようにタイプが同じである場合にのみ有効にすることです。
template <typename T, typename ...Args>
typename std::enable_if<all_same<T, Args...>::value, std::array<T, sizeof...(Args) + 1>>::type
make_array(T && t, Args &&... args)
{
return std::array<T, sizeof...(Args) + 1> { std::forward<T>(t), std::forward<Args>(args)...};
}
どちらの場合も、可変個all_same<Args...>
型の特性が必要になります。ここでは一般化から、であるstd::is_same<S, T>
(減衰がの混合を可能にするために重要であることに注意してくださいT
、T&
、T const &
など):
template <typename ...Args> struct all_same { static const bool value = false; };
template <typename S, typename T, typename ...Args> struct all_same<S, T, Args...>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value && all_same<T, Args...>::value;
};
template <typename S, typename T> struct all_same<S, T>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value;
};
template <typename T> struct all_same<T> { static const bool value = true; };
注ことmake_array()
(十分な最適化フラグ付き!)コピーの一時的によって戻り、コンパイラは右辺値として、あるいはそれ以外の最適化離れ扱いとさせており、std::array
集合型であるため、コンパイラは可能な限り最高の施工方法を選択して自由です。
最後に、make_array
イニシャライザを設定するときにコピー/移動の構築を回避できないことに注意してください。したがってstd::array<Foo,2> x{Foo(1), Foo(2)};
、コピー/移動はありませんがauto x = make_array(Foo(1), Foo(2));
、引数がに転送されるときに2つのコピー/移動がありますmake_array
。可変長初期化子リストを字句的にヘルパーに渡して型とサイズを推定することができないので、あなたはそれを改善できるとは思いません-プリプロセッサーsizeof...
に可変個引数の関数がある場合、おそらくそれは可能ですが、できませんコア言語内。