gpt4 book ai didi

c++ - 如何在 CRTP 基类中根据 "op"实现 "op="?

转载 作者:行者123 更新时间:2023-11-30 02:46:41 28 4
gpt4 key购买 nike

Herb Sutter 的 Guru of the Week #4, "Class Mechanics" ,教导重载运算符的“a op b”形式应该根据“a op= b”形式实现(参见解决方案中的第 4 点).

例如,他展示了如何为 + 运算符执行此操作:

T& T::operator+=( const T& other ) {
//...
return *this;
}

T operator+( T a, const T& b ) {
a += b;
return a;
}

他指出 operator+ 中的第一个参数是有意按值传递的,因此如果调用者传递一个临时值,它可以被移动。

请注意,这要求 operator+ 是非成员函数。

我的问题是,如何将此技术应用于 CRTP 中的重载运算符?基类?

假设这是我的 CRTP 基类及其 operator+=:

template <typename Derived>
struct Base
{
//...

Derived operator+=(const Derived& other)
{
//...
return static_cast<Derived&>(*this);
}
};

如果我放弃“按值传递第一个参数”优化,我可以看到如何根据 operator+=operator+ 实现为成员函数:

template <typename Derived>
struct Base
{
//...

Derived operator+(const Derived& other) const
{
Derived result(static_cast<const Derived&>(*this);
result += other;
return result;
}
};

但是有没有办法在使用优化的同时做到这一点(并因此使 operator+ 成为非成员)?

最佳答案

实现Herb建议的正常方式如下:

struct A {
A& operator+=(cosnt A& rhs)
{
...
return *this;
}
friend A operator+(A lhs, cosnt A& rhs)
{
return lhs += rhs;
}
};

将其扩展到 CRTP:

template <typename Derived>
struct Base
{
Derived& operator+=(const Derived& other)
{
//....
return *self();
}
friend Derived operator+(Derived left, const Derived& other)
{
return left += other;
}
private:
Derived* self() {return static_cast<Derived*>(this);}
};

如果您尽量避免使用 friend在这里,您意识到它几乎是这样的:

 template<class T>
T operator+(T left, const T& right)
{return left += right;}

但仅对派生自 Base<T> 的事物有效,这样做既棘手又难看。

template<class T, class valid=typename std::enable_if<std::is_base_of<Base<T>,T>::value,T>::type>
T operator+(T left, const T& right)
{return left+=right;}

此外,如果它是 friend类的内部,那么它在技术上不在全局命名空间中。所以如果有人写了一个无效的 a+b Base 都不是,那么您的过载将不会导致 1000 行错误消息。免费的类型特征版本可以。


至于为什么要签名:Values for mutable,const& for immutable。 && 实际上仅适用于移动构造函数和其他一些特殊情况。

 T operator+(T&&, T) //left side can't bind to lvalues, unnecessary copy of right hand side ALWAYS
T operator+(T&&, T&&) //neither left nor right can bind to lvalues
T operator+(T&&, const T&) //left side can't bind to lvalues
T operator+(const T&, T) //unnecessary copies of left sometimes and right ALWAYS
T operator+(const T&, T&&) //unnecessary copy of left sometimes and right cant bind to rvalues
T operator+(const T&, const T&) //unnecessary copy of left sometimes
T operator+(T, T) //unnecessary copy of right hand side ALWAYS
T operator+(T, T&&) //right side cant bind to lvalues
T operator+(T, const T&) //good
//when implemented as a member, it acts as if the lhs is of type `T`.

如果移动比复制快得多,并且您正在处理交换运算符,您可能有理由重载这四个。但是,它适用于交换运算符(其中 A?B==B?A,所以 + 和 *,但不适用于 -、/或 %)。对于非交换运算符,没有理由不使用上面的单个重载。

T operator+(T&& lhs , const T& rhs) {return lhs+=rhs;}
T operator+(T&& lhs , T&& rhs) {return lhs+=rhs;} //no purpose except resolving ambiguity
T operator+(const T& lhs , const T& rhs) {return T(lhs)+=rhs;} //no purpose except resolving ambiguity
T operator+(const T& lhs, T&& rhs) {return rhs+=lhs;} //THIS ONE GIVES THE PERFORMANCE BOOST

关于c++ - 如何在 CRTP 基类中根据 "op"实现 "op="?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23377405/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com