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; }
};
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
3 votes
@PavelAnossov : Mais comme les inséreurs insistent pour insérer un objet du type contenu dans le conteneur, vous payez une pénalité (généralement un déplacement) pour insérer un type différent. L'emplacement éviterait cette pénalité.
0 votes
Pouvez-vous nous donner un cas d'utilisation raisonnable ?
4 votes
@Walter : Cas d'utilisation 1 : J'ai un conteneur d'ints et un conteneur d'objets, où chaque objet peut être initialisé avec un int. Je veux ajouter au conteneur d'objets une séquence de nouveaux objets initialisés avec des ints, et je veux le faire de la manière la plus efficace possible. Cas d'utilisation 2 : j'ai une bibliothèque d'algorithmes dans le style STL, mais ils opèrent sur plusieurs séquences d'entrée à la fois (comme la version à deux séquences de std::transform). Je veux ajouter de nouveaux objets au début d'une séquence, où les n arguments du constructeur des nouveaux objets sont tirés des n séquences d'entrée que je traite.
2 votes
@Walter : insérer dans un tableau d'objets où les objets sont grands et/ou des types hérités qui sont copiables mais non déplaçables. Ce n'est pas vraiment un problème.
0 votes
@KnowItAllWannabe Le problème est que
back_emplacer
lorsqu'il est utilisé avec des algorithmes, n'accepterait qu'un seul argument de constructeur (comme votreint
). Des algorithmes tels questd::generate
n'offrent pas la possibilité de passer plusieurs arguments à transmettre àback_emplacer
.