40

標準テンプレートstd::pairstd::arrayは の特殊なケースでありstd::tuple、非常に類似した一連の機能を持つ必要があるのは当然のことです。

ただし、3 つのうちで一意に、ピース単位の構築std::pairが可能です。つまり、型とが一連の引数とから構築できる場合、道徳的に言えば、ペアを作成できます。T1T2a1, a2, ...b1, b2, ...

"pair<T1, T2> p(a1, a2, ..., b1, b2, ...)"

直接。実際には、これは次のように記述されます。

std::pair<T1, T2> p(std::piecewise_construct,
                    std::forward_as_tuple(a1, a2, ...),
                    std::forward_as_tuple(b1, b2, ...));

質問:配列とタプルに同じ区分的構成可能性が存在しないのはなぜですか? 何か重大な理由があるのでしょうか、それとも単純な省略ですか? たとえば、次のようにすると便利です。

std::tuple<T1, T2, T3> t(std::piecewise_construct,
                         std::forward_as_tuple(a1, a2, ...),
                         std::forward_as_tuple(b1, b2, ...),
                         std::forward_as_tuple(c1, c2, ...));

これができない理由はありますか?[編集: それとも、ピースごとの構築の目的を完全に誤解していますか?]

(タプルのベクトルをデフォルトの要素値で初期化したい状況が実際にあります。これは、各タプル要素の型を再度綴ることなく、引数から直接構築することを好みます。)

4

3 に答える 3

17

質問:配列とタプルに同じ区分的構成可能性が存在しないのはなぜですか?

私の記憶では、ピース単位の構築が追加されたstd::pair理由は 1 つだけです。つまり、ペア要素の uses-allocator 構築をサポートするためです。つまり、アロケーターを使用して構築をサポートしている場合に、アロケーターを提供して条件付きで要素に渡すことができるようにするためです ([allocator を参照)。 .uses] を標準で使用)。

C++0x プロセスのある時点で、std::pair現在の 2 倍のコンストラクターがありました。すべてのコンストラクターは、対応する「アロケーター拡張」バージョンをstd::allocator_arg_t持ち、アロケーター引数をとります。

template<class T, class U>
  struct pair {
    pair();
    pair(allocator_arg_t, const Alloc&);
    template<class TT, class UU>
      pair(TT&&, UU&&);
    template<class Alloc, class TT, class UU>
      pair(allocator_arg_t, const Alloc&, TT&&, UU&&);
    // etc.

の非常識な複雑さについて、冗談のようなものがありました (ハハ、ただ真面目なだけです) std::pair。要素にアロケータを渡すためのサポートは から削除されstd::pair、 に移動されましたstd::scoped_allocator_adaptor。これは、アロケータを使用して要素を構築する必要があるかどうかを検出する役割を果たします ( [allocator.adaptor.members] でconstructポインタを取得するオーバーロードを参照してください)。std::pair

ピース単位の構築の良い結果は、ペア要素の「配置」スタイルの初期化を実行できることです。これにより、移動もコピーもできない型のペアが許可されますが、私の知る限り、それは設計の目標ではありませんでした。

したがって、tupleそれをサポートしない理由は、単純化するために機能が発明され、C++03 の非常に単純なpair型から C++0x の笑い株に膨らんだためです。tupleとにかくC++ 11にとっては新しいものでした)。scoped_allocator_adaptorまた、任意の数の要素のタプルを処理するように拡張すると、そのアダプターがはるかに複雑になります。

に関してはstd::array、それは(理由により)集約型であるためpiecewise_construct_t、非集約にしないとコンストラクターを追加することはできません。

于 2014-07-22T13:02:15.847 に答える
1

これがタプルのピース単位の実装です(omit「キーワード」で値を省略することもできます)。ゼロ オーバーヘッド (コピー/移動なし - 直接構築):

http://coliru.stacked-crooked.com/a/6b3f9a5f843362e3

#include <tuple>
#include <utility>
#include <typeinfo>


struct Omit{} omit;


template <class Field, class ...Fields>
struct TupleHolder{
    using fieldT = Field;
    using nextT = TupleHolder<Fields...>;

    Field field;
    TupleHolder<Fields...> next;

    TupleHolder(){}

    template <class ...ValuesRef>
    TupleHolder(Omit, ValuesRef&& ... values)
            : next( std::forward<ValuesRef>(values)... )
    {}

    template <std::size_t ...ids, class FieldValue, class ...ValuesRef>
    TupleHolder(std::index_sequence<ids...>, FieldValue&& field, ValuesRef&& ... values)
            :
            field( std::get<ids>(std::forward<FieldValue>(field))... ),
            next( std::forward<ValuesRef>(values)... )

    {};


    template <class FieldValue, class ...ValuesRef>
    TupleHolder(FieldValue&& field, ValuesRef&& ... values)
            : TupleHolder(
            std::make_index_sequence<
                    std::tuple_size< std::decay_t<FieldValue> >::value
            >(),
            std::forward<FieldValue>(field),
            std::forward<ValuesRef>(values)...
    )
    {}

};


template <class Field>
struct TupleHolder<Field>{
    using fieldT = Field;
    Field field;    // actually last

    TupleHolder(){}
    TupleHolder(Omit){}

    template <std::size_t ...ids, class FieldValue>
    TupleHolder(std::index_sequence<ids...>, FieldValue&& field)
            :
            field( std::get<ids>(std::forward<FieldValue>(field))... )
    {}


    template <class FieldValue>
    TupleHolder(FieldValue&& field)
            : TupleHolder(
            std::make_index_sequence<
                    std::tuple_size< std::decay_t<FieldValue> >::value
            >(),
            std::forward<FieldValue>(field)
    )
    {}
};



template <int index, int target_index, class T>
struct GetLoop{
    using type = typename T::nextT;

    constexpr static decltype(auto) get(T& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                data.next
        );
    }

    constexpr static decltype(auto) get(const T& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                data.next
        );
    }


    constexpr static decltype(auto) get(T&& data) noexcept{
        return GetLoop<index+1, target_index, typename T::nextT>::get(
                std::forward<type>(data.next)
        );
    }
};

template <int target_index, class T>
struct GetLoop<target_index, target_index, T>{
    using type = typename T::fieldT;

    constexpr static type& get(T& data) noexcept{
        return data.field;
    }

    constexpr static const type& get(const T& data) noexcept{
        return data.field;
    }

    constexpr static type&& get(T&& data) noexcept{
        return std::forward<type>(data.field);
    }
};


// ----------------------------------------------------------------------------------
//                          F R O N T E N D
// ----------------------------------------------------------------------------------

template<class ...FieldTypes>
struct TuplePiecewise{
    using fieldsT = TupleHolder<FieldTypes...>;
    TupleHolder<FieldTypes...> data;

    TuplePiecewise(){}

   // allow copy constructor
   TuplePiecewise(TuplePiecewise& other)
            : TuplePiecewise(static_cast<const TuplePiecewise&>(other)) {}


    template <class ...ValuesRef>
    explicit constexpr TuplePiecewise(ValuesRef&& ... values) noexcept
            : data( std::forward<ValuesRef>(values)... ){}

    TuplePiecewise( const TuplePiecewise& other ) = default;
    TuplePiecewise( TuplePiecewise&& other ) = default;


    static constexpr const std::size_t size = sizeof...(FieldTypes);
};


template<int index, class ...FieldTypes>
constexpr decltype(auto) get(TuplePiecewise<FieldTypes...> &&list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  std::move(list.data) );
}

template<int index, class ...FieldTypes>
constexpr decltype(auto) get(TuplePiecewise<FieldTypes...> &list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  list.data );
}

template<int index, class ...FieldTypes>
constexpr decltype(auto) get(const TuplePiecewise<FieldTypes...> &list) noexcept {
    return GetLoop<0, index, typename TuplePiecewise<FieldTypes...>::fieldsT >::get(  list.data );
}

使用法:

TuplePiecewise< CopyTest, int&, string, int >
list (forward_as_tuple(45,63), forward_as_tuple(i), forward_as_tuple("hghhh"), omit );
decltype(auto) o = get<2>(list);
cout << o;

タプル内のタプル (ゼロ オーバーヘッド):

TuplePiecewise< string, TuplePiecewise<int,int> > list4(forward_as_tuple("RRR"), forward_as_tuple(forward_as_tuple(10), forward_as_tuple(20)));
于 2015-08-20T16:04:18.853 に答える