1
// 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(),因为其他一些类使用 astd::stack而不是 a std::vector。我将不得不创建多个重载并有更多的代码重复。

有没有一种通用的方法/习惯来取代返回值

4

3 回答 3

4

根据我们在评论中关于使用 SFINAE 允许在任何类型的容器上放置的讨论(无论它支持emplace还是emplace_back),这里是一个示例实现。

您只需要一种方法来检测是否emplace可用emplace_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()使用示例和你的实际代码之间的差距,但现在应该不会太难。;)

于 2013-08-23T16:35:25.027 回答
3

这是一种方法,您可以将代码传递到GetRangeemplace 中,而无需知道您要放入的内容是什么:

template<typename Emplacer>
void GetRange( Emplacer emplace ) {
  int beg, end;
  // ...
  emplace( beg, end );
}

std::vector<Range> ranges;
inline void intensive()
{
   GetRange( [&]( int b, int e ) {
     ranges.emplace_back( b, e );
   } );
}
于 2013-08-23T18:21:31.767 回答
1

不,正在用getRange()whereemplace_backvector.

于 2013-08-23T14:43:48.493 回答