Лучший пример, который мне известен, это Boost.Phoenix , который перегружает этот оператор для реализации ленивого доступа к элементу.
Для тех, кто незнаком с Phoenix, это очень изящная библиотекасоздание акторов (или функциональных объектов), которые выглядят как нормальные выражения:
( 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==
.- применительно к субъекту arg1
эти операторы возвращают другого субъекта.Диапазон выражений, которые можно построить таким образом, чрезвычайно велик:
// 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;
Что не удастся, потому что, конечно, у актеров Феникса нет члена ValidStateBit
.Феникс обходит это, перегрузив 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: актер, возвращающий
MyObj *
- RHS: адрес члена
Возвращает субъект, который оценивает LHS и ищет в нем указанного члена.(NB: Вы действительно, действительно хотите убедиться, что 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;
}