gpt4 book ai didi

c++ - 自由 operator->* 重载是邪恶的吗?

转载 作者:IT老高 更新时间:2023-10-28 12:31:20 28 4
gpt4 key购买 nike

我在阅读 refuting the notion 之后的第 13.5 节内置运算符不参与重载决议,并注意到没有关于 operator->* 的部分。它只是一个通用的二元运算符。

它的兄弟operator->operator*operator[]都要求是非静态成员函数。这排除了将自由函数重载定义为运算符通常用于从对象获取引用。但是不常见的 operator->* 被省略了。

尤其是 operator[] 有很多相似之处。它是二进制的(他们错过了使其成为 n 元的黄金机会),它在左侧接受某种容器,在右侧接受某种定位器。它的特殊规则部分 13.5.5 似乎没有任何实际效果,除了取缔自由函数。 (而且这种限制甚至排除了对交换性的支持!)

例如,这是perfectly legal :

#include <utility>
#include <iostream>
using namespace std;

template< class T >
T &
operator->*( pair<T,T> &l, bool r )
{ return r? l.second : l.first; }

template< class T >
T & operator->*( bool l, pair<T,T> &r ) { return r->*l; }

int main() {
pair<int, int> y( 5, 6 );
y->*(0) = 7;
y->*0->*y = 8; // evaluates to 7->*y = y.second
cerr << y.first << " " << y.second << endl;
}

很容易找到用途,但替代语法往往没那么糟糕。例如,vector 的缩放索引:

v->*matrix_width[2][5] = x; // ->* not hopelessly out of place

my_indexer<2> m( v, dim ); // my_indexer being the type of (v->*width)
m[2][5] = x; // it is probably more practical to slice just once

标准委员会是否忘记防止这种情况发生,是否认为它太丑而无法打扰,或者是否存在实际用例?

最佳答案

我知道的最好的例子是Boost.Phoenix ,这会重载此运算符以实现惰性成员访问。

对于不熟悉 Phoenix 的人来说,它是一个非常漂亮的库,用于构建看起来像普通表达式的 Actor (或函数对象):

( arg1 % 2 == 1 )     // this expression evaluates to an actor
(3); // returns true since 3 % 2 == 1

// these actors can also be passed to standard algorithms:
std::find_if(c.begin(), c.end(), arg1 % 2 == 1);
// returns iterator to the first odd element of c

它通过重载 operator%operator== 实现上述目的。 - 应用于actor arg1 这些操作符返回另一个actor。可以用这种方式构建的表达式范围非常大:

// print each element in c, noting its value relative to 5:
std::for_each(c.begin(), c.end(),
if_(arg1 > 5)
[
cout << arg1 << " > 5\n"
]
.else_
[
if_(arg1 == 5)
[
cout << arg1 << " == 5\n"
]
.else_
[
cout << arg1 << " < 5\n"
]
]
);

在您使用 Phoenix 一段时间后(不是说您会返回),您将尝试以下操作:

typedef std::vector<MyObj> container;
container c;
//...
container::iterator inv = std::find_if(c.begin(), c.end(), arg1.ValidStateBit);
std::cout << "A MyObj was invalid: " << inv->Id() << std::endl;

这会失败,因为 Phoenix 的 Actor 当然没有成员 ValidStateBit。 Phoenix 通过重载 operator->* 来解决这个问题:

(arg1 ->* &MyObj::ValidStateBit)              // evaluates to an actor
(validMyObj); // returns true

// used in your algorithm:
container::iterator inv = std::find_if(c.begin(), c.end(),
(arg1 ->* &MyObj::ValidStateBit) );

operator->*的参数是:

  • LHS: Actor 返回MyObj *
  • RHS:成员(member)地址

它返回一个评估 LHS 并在其中查找指定成员的参与者。 (注意:你真的,真的想确保 arg1 返回 MyObj * - 在你得到一些东西之前你没有看到大量的模板错误Phoenix 出错了。这个小程序产生了 76,738 个痛苦字符(Boost 1.54,gcc 4.6):

#include <boost/phoenix.hpp>
using boost::phoenix::placeholders::arg1;

struct C { int m; };
struct D { int n; };

int main() {
( arg1 ->* &D::n ) (new C);
return 0;
}

关于c++ - 自由 operator->* 重载是邪恶的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2696864/

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