c++boostfunctorboost-phoenix

replacing a unary functor with a boost::phoenix actor


I have a Visual Studio 2008 C++ application where I would like to replace a unary functor with a boost::phoenix lambda expression.

In my case, I have list of objects with containing a string. I want to remove all objects with a string that does not match the specified one. So, I use an algorithm like this:

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;
}

This works fine. But, I'd like to clean up my code a bit and get rid of the NotMatchType functor and replace it with a simple lambda expression like this:

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() );

obviously, this doesn't work.

I have also tried: ( arg1->*&Foo::my_type ).compare( some_type ) != 0

What do I need to do to make the boost:phoenix:actor look like a Foo object?


Solution

  • Given two strings lhs and rhs, then lhs == rhs is specified to be semantically equivalent to lhs.compare(rhs) == 0. In other words, what your functor is doing is equivalent to doing f.my_type != t_.

    With that in mind, you can express what you want with Phoenix as:

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

    For the record, you were calling a member compare on a Phoenix actor. Since that member belongs to std::string though, that's not what you want. I can get the following to work:

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

    where that last line is the final functor. But that's not good because there is no reliable way to get the address of an overloaded member of a Standard type. In other words the second line in the above is not guaranteed to compile.

    For future reference I prefer lambdas when calling an overloaded member:

    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