I have used vector::emplace_back
in order to avoid constructing temporal objects while filling a vector. Here you have a simplified version:
class Foo {
public:
Foo(int i, double d) : i_(i), d_(d) {}
/* ... */
};
std::vector<Foo> v;
v.reserve(10);
for (int i = 0; i < 10; i++)
v.emplace_back(1, 1.0);
But I wanted to use std::fill_n
instead:
v.reserve(10);
std::fill_n(std::back_inserter(v), 10, Foo(1, 1.0));
In this way, temporal copies will be created, though. I do not know how to use emplace
in this situation. I guess I would need something like std::back_emplacer
, but I could not find such a thing. Is that part of C++11, but not implemented in GCC yet? If it is not part of C++11, is there any other way to do that?
It's common to use tuples to ease the pass a variadic number of items (in this case, parameters to forward to
emplace_back
), with a little technique to unpack the tuple back. As such it is possible to write aback_emplacer
utility by requiring the user to make use of the tuple factory functions (one ofstd::make_tuple
,std::tie
,std::forward_as_tuple
) where it make sense:A demonstration of the code is available. In your case you'd want to call
std::fill_n(back_emplacer(v), 10, std::forward_as_tuple(1, 1.0));
(std::make_tuple
is also acceptable). You'd also want the usual iterator stuff to make the feature complete -- I recommend Boost.Iterators for that.I must really stress however that such a utility doesn't bring much when used with
std::fill_n
. In your case it would save the construction of the temporaryFoo
, in favour of a tuple of references (a tuple of values if you were to usestd::make_tuple
). I leave it to the reader to find some other algorithm whereback_emplacer
would be useful.You are right that there is no
back_emplacer
in the standard. You could perfectly write one yourself, but what for ?When you call
emplace_back
, you have to provide the arguments for the constructor (any constructor):vec.emplace_back(1, 2)
for example. However, you cannot arbitrarily pass tuples of arguments in C++, so theback_emplacer
would be limited to unary constructor.In the case of
fill_n
, you provide an argument that will be copied, and then bothback_inserter
andback_emplacer
would call the same copy constructor with the same argument.Note that there is the
generate
andgenerate_n
algorithms to build new elements. But likewise any temporary copy will probably be elided.Therefore I think the need for a
back_emplacer
is rather light, mostly because of the language non-support of multiple return values.EDIT
If you look at the comments below you will realize that using a combination
std::forward_as_tuple
andstd::is_constructible
it could be possible to write aback_emplacer
mechanism. Thanks to Luc Danton for the breakthrough.There won't be any "temporal copies" made. There will be exactly one temporary, the one you passed to
fill_n
. And it will be copied into each value.And even if there was a
back_emplacer
, what would you call it with? Theemplace
familiy of functions take constructor parameters;fill_n
takes an object to copy into the iterator.I've seen @LucDanton's answer above (https://stackoverflow.com/a/12131700/1032917) and I still cannot see the point of making the code overly complicated (apart from the fact it was written back in 2012, but even given that...). Anyway, I find the following code as functional as Luc's:
And with CTAD in C++17, you can even get rid of
back_emplacer
and writeback_emplace_iterator(my_container)
without explicitly giving the template arguments.I recently submitted an
emplace_iterator
class and related utility function to the folly library. I believe it solves the original question and supports automatic unzipping ofstd::tuple
arguments passed tooperator=
.https://github.com/facebook/folly/blob/master/folly/Iterator.h
folly::make_emplace_args
is analogous tostd::make_tuple
but results in perfect forwarding of its arguments to theWidget
constructor. (std::make_tuple
and similar may result in additional copies and does not preserve lvalue vs rvalue typedness.) In this specific example, usingstd::make_tuple
would have the same effect though.RVO allows the return value of a function to be elided directly into where it is going to be stored.
While logically a temporary is created, in actual fact no temporary is created. And you have access to all variables in the surrounding scope to decide how to create the element, not just constants, if you want them.