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

版本2 总是比版本1更快。

实际上,getRange()被多个类使用。如果要应用版本2,将有很多代码重复。

另外,我不能将ranges传递为对getRange()的非常量引用,因为其他一些类使用std::stack而不是std::vector。我将不得不创建多个重载并进行更多的代码重复。

是否有放置返回值的通用方法/惯用法?

最佳答案

在关于使用SFINAE允许在任何类型的容器上放置(无论它是否支持emplaceemplace_back)的注释中的讨论之后,这里是一个示例实现。

您只需要一种方法来检测emplaceemplace_back是否可用,并相应地调度该调用。为此,我们将使用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)...);
}

@DyP的荣誉,他为提供了许多更好,更短的C++ 11解决方案(请参见注释)。以前基于特征的解决方案(修订版3和4)更加冗长。

使用它非常简单:
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>>();
}

我将让您弥合test_emplace()使用示例和您的实际代码之间的鸿沟,但是现在不应该太难了。 ;)

10-07 13:57