一遍又一遍地重载运算符
Overload operator over and over
我在自己的向量中重载了运算符 << class,它将按如下方式工作
int main() {
my_vector<int> vec;
vec << 1 << 2 << 3; // will add elements at end [ 1, 2, 3 ]
display(vec);
}
这完全符合我的要求,但我想提高效率我这样做了
10 << vec; // will add element at begin [ 10, 1, 2, 3 ]
But this goes wrong when I do it multiple times like
20 << 10 << vec; // this does [ 20480, 1, 2, 3 ];
首先对 20 << 10 进行操作,然后对 20480 << vec
I want to process it like [ 20, 10, 1, 2, 3];
发生这种情况是因为运算符 precedence/associativity。编译器首先在20
和10
之间执行<<操作,然后在结果和vec
之间执行另一个<<操作。这是因为如果您有多个 <<
运算符,它们将从左到右处理。
使用括号应该可以解决:
20 << (10 << vec);
这告诉编译器首先执行10
和vec
之间的操作,然后在结果和20
之间执行另一个操作。
(假设您正确实现了运算符重载)。
旁注:
请不要以不希望的方式重载运算符。这会让人感到困惑,并且很难 read/maintain 您的代码。
我无法想象在专业代码中会有这样的超载,但它可以只是为了好玩。
正题
现在您的第二种方法不起作用,因为运算符:<<
>>
具有从左到右的关联性。这意味着当你写:
vec << 1 << 2 << 3;
这相当于:
(((vec << 1) << 2) << 3);
当你写的时候:
20 << 10 << vec;
实际结果是:
((20 << 10) << vec);
因此它首先计算 20 << 10
并将其结果提供给您的重载版本的运算符 <<
。
理论上,您可以重载具有从右到左关联性的其他运算符(例如 <<=
、>>=
),以实现您的目标,但正如我指出的那样,这是非常糟糕的练习,这会使情况变得更糟。
一个可能的解决方案是创建一个代理对象,甚至是一个完整的矢量对象,它聚合要插入的元素。
界面大致如下:
vec_front_inserter(20) >> 10 >> my_vec;
请注意,我建议使用提取运算符 (>>
) 来表示前插入,因为它对我来说读起来更好,但请随意改回插入运算符 (<<
)如果你不喜欢这个。
您的实施需要:
- 定义一个
operator>>(const my_vector&, my_vector&)
来表示将一个向量插入另一个向量。
- 创建一个代理
vec_front_inserter
class 已定义 operator>>(vec_front_inserter&, int)
,并在内部持有 my_vector
。
- 定义一个
operator>>(const vec_front_inserter&, my_vector&)
在my_vector
前面插入元素。
class vec_front_inserter {
public:
vec_front_inserter() {}
vec_front_inserter(int seed) {
_data.push_front(seed);
}
friend vec_front_inserter& operator>>(vec_front_inserter& proxy, int value);
friend my_vector& operator>>(const vec_front_inserter& proxy, my_vector& vec);
private:
my_vector _data;
};
vec_front_inserter& operator>>(vec_front_inserter& proxy, int value) {
_data.push_back(value);
}
my_vector& operator>>(const vec_front_inserter& proxy, my_vector& vec) {
vec.insert_front(proxy._data);
}
这和我对字符串连接的感觉很像。
你可以这样做:
std::string concat = std::string("foo") + "bar" + "biz" + "baz";
但是你不能这样做:
std::string fail = "foo" + "bar" + "biz" + "baz";
我在自己的向量中重载了运算符 << class,它将按如下方式工作
int main() {
my_vector<int> vec;
vec << 1 << 2 << 3; // will add elements at end [ 1, 2, 3 ]
display(vec);
}
这完全符合我的要求,但我想提高效率我这样做了
10 << vec; // will add element at begin [ 10, 1, 2, 3 ]
But this goes wrong when I do it multiple times like
20 << 10 << vec; // this does [ 20480, 1, 2, 3 ];
首先对 20 << 10 进行操作,然后对 20480 << vec
I want to process it like [ 20, 10, 1, 2, 3];
发生这种情况是因为运算符 precedence/associativity。编译器首先在20
和10
之间执行<<操作,然后在结果和vec
之间执行另一个<<操作。这是因为如果您有多个 <<
运算符,它们将从左到右处理。
使用括号应该可以解决:
20 << (10 << vec);
这告诉编译器首先执行10
和vec
之间的操作,然后在结果和20
之间执行另一个操作。
(假设您正确实现了运算符重载)。
旁注:
请不要以不希望的方式重载运算符。这会让人感到困惑,并且很难 read/maintain 您的代码。 我无法想象在专业代码中会有这样的超载,但它可以只是为了好玩。
正题
现在您的第二种方法不起作用,因为运算符:<<
>>
具有从左到右的关联性。这意味着当你写:
vec << 1 << 2 << 3;
这相当于:
(((vec << 1) << 2) << 3);
当你写的时候:
20 << 10 << vec;
实际结果是:
((20 << 10) << vec);
因此它首先计算 20 << 10
并将其结果提供给您的重载版本的运算符 <<
。
理论上,您可以重载具有从右到左关联性的其他运算符(例如 <<=
、>>=
),以实现您的目标,但正如我指出的那样,这是非常糟糕的练习,这会使情况变得更糟。
一个可能的解决方案是创建一个代理对象,甚至是一个完整的矢量对象,它聚合要插入的元素。
界面大致如下:
vec_front_inserter(20) >> 10 >> my_vec;
请注意,我建议使用提取运算符 (>>
) 来表示前插入,因为它对我来说读起来更好,但请随意改回插入运算符 (<<
)如果你不喜欢这个。
您的实施需要:
- 定义一个
operator>>(const my_vector&, my_vector&)
来表示将一个向量插入另一个向量。 - 创建一个代理
vec_front_inserter
class 已定义operator>>(vec_front_inserter&, int)
,并在内部持有my_vector
。 - 定义一个
operator>>(const vec_front_inserter&, my_vector&)
在my_vector
前面插入元素。
class vec_front_inserter {
public:
vec_front_inserter() {}
vec_front_inserter(int seed) {
_data.push_front(seed);
}
friend vec_front_inserter& operator>>(vec_front_inserter& proxy, int value);
friend my_vector& operator>>(const vec_front_inserter& proxy, my_vector& vec);
private:
my_vector _data;
};
vec_front_inserter& operator>>(vec_front_inserter& proxy, int value) {
_data.push_back(value);
}
my_vector& operator>>(const vec_front_inserter& proxy, my_vector& vec) {
vec.insert_front(proxy._data);
}
这和我对字符串连接的感觉很像。
你可以这样做:
std::string concat = std::string("foo") + "bar" + "biz" + "baz";
但是你不能这样做:
std::string fail = "foo" + "bar" + "biz" + "baz";