使用Boost.Phoenix的运算符 - > *

时间:2011-07-21 11:10:02

标签: c++ boost boost-phoenix

我正在玩凤凰v3试图弄清楚我们是否应该对它进行标准化,而不是目前Bind和Lambda的混合。从文档中我得到的印象是应该可以简化一些表达式。

目前我坚持使用 - > *运算符与STL算法结合使用。以下将编译(Visual Studio 2008 SP1)但不提供预期的输出:

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/mem_fn.hpp>
#include <boost/phoenix.hpp>
using namespace std;
using namespace boost;
using namespace boost::phoenix;
using namespace boost::phoenix::arg_names;

struct A
{
  void f() const { cout << "A"; };
};
struct B
{
  A a() { return A(); };
};

int main()
{
  vector<A> va(1);
  for_each(va.begin(), va.end(), bind(mem_fn(&A::f), arg1));
  for_each(va.begin(), va.end(), arg1->*&A::f);

  vector<B> vb(1);
  for_each(vb.begin(), vb.end(), bind(mem_fn(&A::f), bind(mem_fn(&B::a), arg1)));
  return 0;
}

运行此示例将两次打印出“A”,这两次都是基于绑定的循环。 所以这是我的问题:

  • 为了让基于操作符的循环实际调用A :: f?
  • ,我应该更改什么
  • 如何使用运算符更改双绑定循环?
  • 当你在这些情况下没有指定mem_fn时,任何人都知道为什么VS2008总是在抱怨?我总是收到警告C4180(应用于函数类型的限定符没有意义;忽略)。

提前感谢任何见解。

2 个答案:

答案 0 :(得分:4)

假设:

#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->*,Phoenix文档clearly state

  

成员指针运算符的左侧必须是返回指针类型的actor。

因此,当给定一个对象(在这种情况下为A&)时,必须获取所述对象的地址才能使用operator->* - 因此&arg1。 (另外,因为凤凰演员是懒惰的,所以必须使用额外的一组括号才能获得渴望的仿函数而不是懒惰的仿函数。)


第二个不是那么容易,因为不能只使用运算符 - 因为我们必须有一个代表指针的actor才能使用operator->*,我们需要取B::a结果的地址,但B::a的结果是右值,并且取任何右值的地址都是非法的。我们有两种选择:

  1. B::a的结果存储到变量中,使其成为左值,从而使其成为合法的地址。这可以使用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)()])
        );
    }
    

    显然这很难看。

  2. 使用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)()));
    }
    

答案 1 :(得分:1)

我也不太擅长凤凰,但我认为你不能按照你想要的方式使用 - &gt; *运算符。
如果您将示例更改为

...
    vector<A*> va;
    va.push_back(new A);
    for_each(va.begin(), va.end(), bind(mem_fn(&A::f), arg1));
    for_each(va.begin(), va.end(), (arg1->*&A::f)());
...

你会得到两次A.在这些例子中我只找到了带指针的例子,所以我猜你只能使用带有指针的phoenix - &gt; *运算符。哪个应该可以作为运算符 - &gt; *绑定到指针 来自5.5中的规范:

  

二元运算符 - &gt; *绑定其第二个操作数,该操作数应为   输入“指向T成员的指针”(其中T是完全定义的类)   type)到它的第一个操作数,它应该是“指向T的指针”或   “指向一个T类是明确且易于访问的类的指针   类