为什么使用const引用参数需要重复代码?

时间:2016-01-31 21:39:38

标签: c++

在此interview Stepanov展示了如何在C ++中实现通用max函数。

  

尝试以面向对象的方式实现一个简单的事情,比如max。   我不知道怎么做。使用通用编程我可以   写:

template <class StrictWeakOrdered>
inline StrictWeakOrdered& max(StrictWeakOrdered& x,
StrictWeakOrdered& y) {
return x < y ? y : x;
}

and
template <class StrictWeakOrdered>
inline const StrictWeakOrdered& max(const StrictWeakOrdered& x,
const StrictWeakOrdered& y) {
return x < y ? y : x;
}
     

(你确实需要&amp;和const&amp;)。

为什么需要两次编写代码?这是否需要帮助编译器进行优化或减少错误的约定? maxconst版本的主体相同的特例吗?

N个参数的函数应该有多少有效const和非const排列来定义完整的API?

3 个答案:

答案 0 :(得分:7)

首先,你需要非const版本来允许像

这样的东西
max(a, b) = something;

如果您不想做这些事情,您只需提供const版本即可涵盖所有情况。这基本上就是标准std::max的作用。

您也不需要再提供const和非const的排名,只有所有输入都是非const&才会返回非const。 ,所有其他案例均由const版本妥善处理。

如果您想避免代码重复,可以执行以下操作:

template <class StrictWeakOrdered>
inline StrictWeakOrdered& max(StrictWeakOrdered& x, StrictWeakOrdered& y) {
    const auto &xr = x;
    const auto &yr = y;
    return const_cast<StrictWeakOrdered&>(max(xr, yr));
}

在这种特殊情况下,const_cast是安全的,因为您已经知道输入确实是非const。现在,您只需提供const案例的实现。

因此,不需要提供两次实现,也不应该帮助编译器,但是上述内容是否比Stepanov所做的更具可读性是有争议的。

答案 1 :(得分:7)

您实际上并不需要这两个版本。你可以这样写。

template <class S, class T>
decltype(auto) max(S&& a, T&& b) {
    using Ret = std::conditional_t<
          std::is_const<std::remove_reference_t<S>>::value, S, T>;

    if (b < a)
        return std::forward<Ret>(a);
    return std::forward<Ret>(b);
}

如果其中一个参数为const,则回退到const

答案 2 :(得分:1)

如果您不打算修改参数,可以使用const&版本。一切都应该绑定到const引用。

C ++ 11还引入了参考折叠,模板参数T&&有时也称为universal reference。在这种情况下,当实例化参数类型时,例如,一个int&,我们会int& &&折叠到int&。现在,您可以将函数编写为

template <class T1, class T2>
inline T1 const& max(T1&& x, T2&& y)  {
     T1 const& x_=x;
     T2 const& y_=y;
     return (x_ < y_) ? (y_) : (x_);
}

可以使用const值,临时值(r值)和可变变量来调用它:

int const a=1;
int b=2;
max(b,b) = 23;
std::cout << max(a,a) << max( int{4}, int{5} ) << b << max(int{4}, a);