为什么std :: max返回const&?

时间:2015-01-12 10:40:04

标签: c++ reference return max const

我想找到最大Foo并在其上调用inc(),这是一种非const方法。当然,在找到最大值时,我不想创建任何副本或动作,即我不想要Foo foo = std::max(foo1, foo2)。我尝试编写自己的最大值,g ++坚持要求返回const&。

#include <iostream>

class Foo
{
public:
  Foo(int x) : x_(x) { std::cout << "const" << std::endl; }
  Foo(const Foo& foo) : x_(foo.x_) { std::cout << "copy const" << std::endl; }
  Foo(Foo&& foo) : x_(foo.x_) { std::cout << "move const" << std::endl; }
  bool operator< (const Foo& foo) const { return x_ < foo.x_; }
  bool operator> (const Foo& foo) const { return x_ > foo.x_; }
  void inc() { ++x_; }
  int x_;
};

/*
 * Doesn't compile.  Must return const T& or must accept non-const T&
 *
template<typename T>
inline T& my_max(const T& f1, const T& f2)
{
  return f1 > f2 ? f1 : f2;
}
*
*/

int main()
{
  Foo foo1(6);      
  Foo foo2(7);      
  Foo& foo = std::max(foo1, foo2); //Doesn't compile.  Must be const Foo&. But then next line fails
  foo.inc();
  std::cout << foo.x_ << std::endl;
  return 0;
}

2 个答案:

答案 0 :(得分:2)

这里有2个问题:

  1. 结果中缺少const限定符
  2. 返回对const引用参数
  3. 的引用是危险的

    在这种情况下:

    Foo& foo = std::max(Foo(6), Foo(7));
    

    编译器将在函数调用之前为参数构造临时对象,并在函数调用后将其销毁 - 因此您将最终引用垃圾。当然,如果你总是使用现有的对象,它将起作用 - 但很容易忘记这些限制。

    您可以从参数中删除const,这将解决这两个问题,因为您打算修改对象,它应该没问题。

答案 1 :(得分:2)

template<typename T>
T my_max(T&& f1, T&& f2) {
  return std::forward<T>(f1 > f2 ? f1 : f2);
}

以上是相对坚实的,并将做你需要的。它确实要求两个参数具有相同的r / l / const,而std::max则没有。这就是max使用const&

的原因

可以编写一个更复杂的版本来查找公共引用类别,但它可以以令人惊讶的方式运行。

所以不要被上面的返回值缺少&所迷惑:在你的用例中,上面的内容会返回一个引用。如果传递了rvalues,则返回一个值。

这是对super_max的尝试,如果传递相同类型的左值,则返回左值。如果传递了两种不同的类型或rvalue,则返回一个副本:

template<class A, class B>
struct max_return:std::common_type<A,B>{};
template<class A>
struct max_return<A&,A&>{
  using type=A&;
};
template<class A, class B>
using max_return_t = typename max_return<A,B>::type;

template<class T, class U>
max_return_t<T,U> super_max(T&& t, U&& u) {
  if (t < u)
    return std::forward<U>(u);
  else
    return std::forward<T>(t);
}

它也只使用<,并且更喜欢左手边的领带。

live example