Дано:
#include <algorithm>
#include <vector>
#include <iostream>
#include <boost/phoenix.hpp>
struct A
{
void f() const { std::cout << "A\n"; };
};
struct B
{
A a() const { return A(); };
};
Первый способ легко исправить:
int main()
{
using boost::phoenix::arg_names::arg1;
std::vector<A> va(1);
std::for_each(va.begin(), va.end(), (&arg1->*&A::f)());
}
Относительно operator->*
, документы Феникса четко указывают :
В левой части оператора указателя члена должен быть субъект, возвращающий тип указателя.
Следовательно, когда дан объект (в данном случае A&
), нужно взять адрес указанного объекта, чтобы использовать operator->*
- следовательно, &arg1
. (Кроме того, поскольку актеры Феникса ленивы, нужно использовать дополнительный набор скобок, чтобы получить активный функтор, а не ленивый функтор.)
Второй вариант не так прост, так как нельзя использовать только операторы - потому что у нас должен быть актер, представляющий указатель , чтобы использовать operator->*
, нам нужно взять адрес результата B::a
, но результат B::a
является rvalue, и взятие адреса любого rvalue является недопустимым. У нас есть два варианта:
Сохраните результат B::a
в переменной, сделав его lvalue, и, следовательно, сделав законным получение адреса. Это можно сделать с помощью phoenix::let
:
int main()
{
using boost::phoenix::let;
using boost::phoenix::arg_names::arg1;
using boost::phoenix::local_names::_a;
std::vector<B> vb(1);
std::for_each(
vb.begin(),
vb.end(),
(let(_a = (&arg1->*&B::a)())[(&_a->*&A::f)()])
);
}
Очевидно, это довольно уродливо.
Используйте phoenix::bind
вместо operator->*
, поскольку он одинаково хорошо работает со ссылками и указателями, устраняя необходимость в получении адреса результата B::a
:
int main()
{
using boost::phoenix::bind;
using boost::phoenix::arg_names::arg1;
std::vector<B> vb(1);
std::for_each(vb.begin(), vb.end(), bind(&A::f, (&arg1->*&B::a)()));
}