在此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;)。
为什么需要两次编写代码?这是否需要帮助编译器进行优化或减少错误的约定? max
是const
版本的主体相同的特例吗?
N个参数的函数应该有多少有效const
和非const
排列来定义完整的API?
答案 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);