0

Trying to write a generic code to emplace a default constructed object into an std container and return an iterator to it.

with insert the solution is

template<typename C>
typename C::iterator insert(C& container)
{
    return container.insert(container.end(), typename C::value_type());
}

But emplace has no such common interface so I had to specialize it for 2 container types. My best attempt (that did not compile) was:

template<typename C>
auto emplace(C& container)
    -> decltype(container.emplace_back())
{
    return container.emplace_back();
}

template<typename C>
auto emplace(C& container)
    -> decltype(container.emplace().first)
{
    return container.emplace().first;
}

This causes: error: void value not ignored as it ought to be

and I don't understand why my decltype was deduced as void.

Used gcc 4.8.5 with -std=c++11

Edit:

reproduced by

int main() { std::vector v; std::vector::iterator iv = emplace(v);

    std::set<int> s;
    std::set<int>::iterator is = emplace(s);
    return 0;

}

Edit 2:

second attempt

template<typename C>
auto emplace(C& container)
    -> decltype(container.emplace().first)
{
    return container.emplace().first;
}

template<typename C>
auto emplace(C& container)
    -> decltype(container.emplace(container.end()))
{
    return container.emplace(container.end());
}

works for verctor, but set is ambiguous.

Shloim
  • 5,281
  • 21
  • 36

2 Answers2

4

Well, it took me longer than it should've.

emplace_back() only returns the emplaced object since C++17. Before then, it returns void, and even in C++17 the return type is a reference, not an iterator.

It looks like your specialization for emplace_back() should be modified to return container.back() instead.

Quentin
  • 62,093
  • 7
  • 131
  • 191
0

Finally solved it thanks to @Quentin:

// For vector, list and anything push_backable
template<typename C>
auto emplace(C& container)
    -> decltype(container.emplace_back(),container.rbegin())
{
    container.emplace_back();
    return container.rbegin();
}

// For set,unordered_set, and anything that emplace returns a pair.
template<typename C>
auto emplace(C& container)
    -> decltype(container.emplace().first)
{
    return container.emplace().first;
}
Shloim
  • 5,281
  • 21
  • 36