web-dev-qa-db-ja.com

C ++ 11またはC ++ 14に定置イテレータがないのはなぜですか?

C++ 98にはfront_inserterback_inserter、およびinserterがありますが、C++ 11またはドラフトC++ 14にはこれらの定置バージョンはないようです。 front_emplacerback_emplacer、およびemplacerを取得できなかった技術的な理由はありますか?

47

Front_emplacer、back_emplacer、およびemplacerを使用できなかった技術的な理由はありますか?

いいえ、技術的な理由はありません。証拠として、ここにback_emplacerの完全な実装とユースケース1のデモがあります...

#include <iterator>
#include <vector>
#include <iostream>

template<class Container>
class back_emplace_iterator : public std::iterator< std::output_iterator_tag,
                                                   void, void, void, void >
{
protected:
    Container* container;
public:
    typedef Container container_type;

    explicit back_emplace_iterator(Container& x) : container(&x) {}

    template<class T>
    back_emplace_iterator<Container>&
    operator=(T&& t)
    {
        container->emplace_back(std::forward<T>(t));
        return *this;
    }

    back_emplace_iterator& operator*() { return *this; }
    back_emplace_iterator& operator++() { return *this; }
    back_emplace_iterator& operator++(int) { return *this; }
};

template< class Container >
inline back_emplace_iterator<Container>
back_emplacer( Container& c )
{
    return back_emplace_iterator<Container>(c);
}

struct Demo
{
    int i;
    Demo(int i) : i(i) {}
};

int main()
{
    std::vector<int> x = {1,2,3,4,5};

    std::vector<Demo> y;

    std::copy(x.begin(), x.end(), back_emplacer(y));

    for (auto d : y)
        std::cout << d.i << std::endl;
}

考えられる既知の問題:operator=のユニバーサル参照は、暗黙的に生成されたコピー/移動operator=を非表示にしますか?その場合、これらは過負荷解決でユニバーサルリファレンスを上回る方法で明示的に定義する必要があります。

30
Andrew Tomazos

主な使用例は、すでにinserterback_inserter、およびfront_inserterでカバーされています。コンテナに移動するvalue_type &&operator=オーバーロードがすでにあります。 emplacerinserterに対して実行できる唯一のことは、明示的なコンストラクターを呼び出すことです。

container::insertcontainer::Push_back、およびcontainer::Push_frontの一般的なオーバーロードをcontainer::emplacecontainer::emplace_back、およびcontainer::emplace_frontと比較します。

iterator insert( const_iterator pos, const value_type & value );
iterator insert( const_iterator pos, value_type && value );

template< class... Args > 
iterator emplace( const_iterator pos, Args&&... args );

void Push_back( const value_type & value );
void Push_back( value_type && value );

template< class... Args >
void emplace_back( Args&&... args );

void Push_front( const value_type & value );
void Push_front( value_type && value );

template< class... Args >
void emplace_front( Args&&... args );

emplaceバリアントのそれぞれは、値を構成するための引数のパックを取ります。 operator =はちょうど1つの引数を取ります。タプルの引数を取るemplacerを書くことができます。

template<class Container>
class back_emplace_iterator : public std::iterator< std::output_iterator_tag,
                                                   void, void, void, void >
{
protected:
    Container* container;
public:
    typedef Container container_type;

    explicit back_emplace_iterator(Container& x) : container(&x) {}

    template<typename ... Args>
    back_emplace_iterator<Container>&
    operator=(std::Tuple<Args&&...> args)
    {
        std::apply(Container::emplace_back, std::Tuple_cat(std::tie(*container), std::forward<std::Tuple<Args&&...>>(args)));
        return *this;
    }

    back_emplace_iterator& operator*() { return *this; }
    back_emplace_iterator& operator++() { return *this; }
    back_emplace_iterator& operator++(int) { return *this; }
};
3
Caleth