【问题标题】:replacing a unary functor with a boost::phoenix actor用 boost::phoenix 演员替换一元函子
【发布时间】:2011-08-29 18:42:57
【问题描述】:

我有一个 Visual Studio 2008 C++ 应用程序,我想用 boost::phoenix lambda 表达式替换一元仿函数。

就我而言,我有一个包含字符串的对象列表。我想删除与指定字符串不匹配的所有对象。所以,我使用这样的算法:

struct Foo
{
    std::string my_type;
};

struct NotMatchType
{
    NotMatchType( const std::string& t ) : t_( t ) { };
    bool operator()( const Foo& f ) const
    {
        return f.my_type.compare( t_ ) != 0;
    };
    std::string t_;
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector< Foo > list_of_foo;

    /*populate with objects*/

    std::string some_type = "some type";

    list_of_foo.erase(
        std::remove_if( list_of_foo.begin(),
                        list_of_foo.end(),
                        NotMatchType( some_type ) ),
        list_of_foo.end() );

    return 0;
}

这很好用。但是,我想稍微清理一下我的代码并去掉 NotMatchType 函子,并用一个简单的 lambda 表达式替换它,如下所示:

using boost::phoenix::arg_names::arg1;

list_of_foo.erase(
    std::remove_if( list_of_foo.begin(),
                    list_of_foo.end(),
                    arg1.my_type.compare( some_type ) != 0 ),
    list_of_foo.end() );

显然,这是行不通的。

我也试过:( arg1-&gt;*&amp;Foo::my_type ).compare( some_type ) != 0

我需要做什么才能使 boost:phoenix:actor 看起来像 Foo 对象?

【问题讨论】:

    标签: c++ boost functor boost-phoenix


    【解决方案1】:

    直接从 Phoenix 使用 std::string::compare() 非常难看,因为它已经超载,我们需要获取它的地址:

    phx::bind(
        static_cast<int (std::string::*)(std::string const&) const>(
            &std::string::compare
        ),
        phx::cref(some_type),
        phx::bind(&Foo::my_type, arg1)
    ) != 0
    

    但是,如果我们按照 Luc 的提示简单地比较对象相等性,它就会变得更易于管理:

    phx::cref(some_type) != phx::bind(&Foo::my_type, arg1)
    

    【讨论】:

    • 这与使用 boost::bind 有什么不同吗? boost::bind( &amp;Foo::my_type, _1 ) != boost::cref( some_type )?另外,是否有必要使用 cref 来阻止它执行复制?
    • @PaulH :是的,boost::bind 可以在这种情况下工作,但std::bindstd::tr1::bind 不会。是的,如果不使用refcref,将制作一份副本。
    【解决方案2】:

    给定两个字符串lhsrhs,则lhs == rhs 被指定为在语义上等同于lhs.compare(rhs) == 0。换句话说,你的仿函数所做的就相当于做f.my_type != t_

    考虑到这一点,你可以用 Phoenix 表达你想要的:

    bind(&Foo::my_type, arg1) =! ref(some_type)
    

    为了记录,你打电话给凤凰城演员的成员compare。不过,由于该成员属于std::string,这不是您想要的。我可以让以下工作:

    typedef int (std::string::*compare_type)(std::string const&) const;
    compare_type compare = &std::string::compare;
    bind(compare, bind(&Foo::my_type, arg1), "") != 0;
    

    最后一行是最终的函子。但这并不好,因为没有可靠的方法来获取标准类型的重载成员的地址。也就是说上面的第二行不保证能编译。

    为了将来参考,我在调用重载成员时更喜欢 lambda:

    auto compare = [](std::string const& lhs, std::string const& rhs)
    { return lhs.compare(rhs); };
    // bind that functor and use it as a Phoenix actor etc
    

    【讨论】:

    • arg1 不代表指针类型,因此在其上使用 operator-&gt;* 是不正确的。 (&amp;arg1)-&gt;*&amp;Foo::my_type != ref(some_type) 应该可以工作。
    • lambdas(作为 c++11 的一部分)在 Visual Studio 2008 中不可用
    • @ildjarn 我不关注。 operator-&gt;* 过载;我展示的代码最终会编译。
    • @Luc : From the docs: "成员指针运算符的左边必须是返回指针类型的actor。" 在这种情况下,左边size (arg1) 返回引用类型,而不是指针类型。
    • @Luc Danton - @ildjarn 是正确的。虽然应用程序会编译,但我开始收到错误。 Run-Time Check Failure #2 - Stack around the variable 'that' was corrupted. 在 boost/proto/generate.hpp(223) 中
    猜你喜欢
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-05
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多