// VERSION 1
struct Range { int begin, end; };
inline Range getRange()
{
int newBegin, newEnd;
// do calculations
return {newBegin, newEnd};
}
struct Test
{
std::vector<Range> ranges;
inline void intensive()
{
ranges.push_back(getRange());
// or ranges.emplace_back(getRange());
// (gives same performance results)
}
};
// VERSION 2
struct Range { int begin, end; };
struct Test
{
std::vector<Range> ranges;
inline void intensive()
{
int newBegin, newEnd;
// do calculations
ranges.emplace_back(newBegin, newEnd);
}
};
Version 2 is always faster than version 1.
Fact is, getRange()
is used by multiple classes. If I were to apply version 2, there would be a lot of code duplication.
Also, I cannot pass ranges
as a non-const reference to getRange()
, as some other classes use a std::stack
instead of a std::vector
. I would have to create multiple overloads and have more code duplications.
Is there a common way/idiom to emplace the return value?
Following our discussion in the comments about using SFINAE to allow emplacement on any type of container (whether it supports emplace
or emplace_back
), here is an example implementation.
You just need a way to detect whether emplace
or emplace_back
is available, and dispatch the call accordingly. For this purpose, we'll use SFINAE:
namespace detail
{
template<typename T, typename... Args>
auto emplace_impl(int, T& c, Args&&... pp)
-> decltype(c.emplace_back(std::forward<Args>(pp)...))
{
return c.emplace_back(std::forward<Args>(pp)...);
}
template<typename T, typename... Args>
auto emplace_impl(long, T& c, Args&&... pp)
-> decltype(c.emplace(std::forward<Args>(pp)...))
{
return c.emplace(std::forward<Args>(pp)...);
}
} // namespace detail
template<typename T, typename... Args>
auto emplace(T& c, Args&&... pp)
-> decltype(detail::emplace_impl(0, c, std::forward<Args>(pp)...))
{
return detail::emplace_impl(0, c, std::forward<Args>(pp)...);
}
Kudos to @DyP who provided this much nicer and shorter C++11 solution (see comments). The previous traits-based solutions (revisions 3 & 4) were a lot more verbose.
Using it is quite straightforward:
template<typename Container>
void test_emplace()
{
Container c;
emplace(c, 3);
}
int main()
{
test_emplace<std::queue<int>>();
test_emplace<std::stack<int>>();
test_emplace<std::deque<int>>();
test_emplace<std::list<int>>();
test_emplace<std::vector<int>>();
}
I'll let you bridge the gap between my test_emplace()
usage example and your actual code, but it shouldn't be too hard now. ;)