55 votes

Pourquoi n'y a-t-il pas d'itérateurs d'emplacement en C++11 ou C++14 ?

C++98 a front_inserter , back_inserter y inserter mais il ne semble pas y avoir de versions de ces emplacements en C++11 ou dans le projet de C++14. Existe-t-il une raison technique pour laquelle nous ne pourrions pas avoir front_emplacer , back_emplacer y emplacer ?

5 votes

Qu'allez-vous leur attribuer ? Des tuples d'arguments ?

0 votes

@PavelAnossov : Cela permettrait au moins de convertir les constructeurs. *front_inserter(string_vector) = "hello world";

1 votes

@MooingDuck : cela fonctionne déjà avec les inséreurs

34voto

Andrew Tomazos Points 18711

Y a-t-il une raison technique pour laquelle nous ne pourrions pas avoir front_emplacer, back_emplacer et emplacer ?

Non, il n'y a pas de raison technique. Pour preuve, voici une implémentation complète de back_emplacer avec une démonstration de votre cas d'utilisation 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;
}

Problème connu possible : La référence universelle de operator= cacher une copie/déplacement générée implicitement operator= ? Dans l'affirmative, il convient de les définir explicitement de manière à surpasser la référence universelle en matière de résolution des surcharges.

0 votes

J'ai a posé une autre question concernant le problème connu.

0 votes

@MooingDuck : Une classe proxy pour quoi faire ? Allez jeter un coup d'oeil à l'implémentation libstdc++ de back_inserter . Il est en bits/stl_iterator.h .

0 votes

@MooingDuck : La norme C++ exige donc de ne pas utiliser une classe proxy, mais de l'implémenter de la manière indiquée. Voir N3485 24.5.2.2.3.

7voto

Caleth Points 17517

Votre principal cas d'utilisation est déjà couvert par inserter , back_inserter y front_inserter . Il existe déjà un value_type && surcharge de operator= qui se déplacera dans le conteneur. La seule chose emplacer pourrait faire plus inserter est d'appeler des constructeurs explicites.

Comparez les surcharges courantes de container::insert , container::push_back y container::push_front a container::emplace , container::emplace_back y 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 );

Chacun des emplace variants prend un ensemble d'arguments pour construire la valeur. operator = prend exactement un argument. Vous pouvez écrire un emplacer qui prend un tuple d'arguments.

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; }
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X