замена унарного функтора на буст :: актер феникса - PullRequest
1 голос
/ 29 августа 2011

У меня есть приложение Visual Studio 2008 C ++, в котором я хотел бы заменить унарный функтор на выражение лямбда-выражения boost :: phoenix.

В моем случае у меня есть список объектов, содержащих строку.Я хочу удалить все объекты со строкой, которая не соответствует указанной.Итак, я использую алгоритм, подобный этому:

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 и заменить его на простое лямбда-выражение, подобное этому:

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->*&Foo::my_type ).compare( some_type ) != 0

Что мне нужно сделать, чтобы буст: phoenix: actor выглядел как Foo объект?

Ответы [ 2 ]

4 голосов
/ 30 августа 2011

Использование 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

Однако, если мы последуем подсказке Люка и просто сравним объектное равенство, он станет болееуправляемый:

phx::cref(some_type) != phx::bind(&Foo::my_type, arg1)
3 голосов
/ 29 августа 2011

Учитывая две строки lhs и rhs, тогда lhs == rhs определяется как семантически эквивалентный lhs.compare(rhs) == 0. Другими словами, то, что делает ваш функтор, эквивалентно тому, что вы делаете f.my_type != t_.

Имея это в виду, вы можете выразить то, что вы хотите с Фениксом, как:

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;

где последняя строка является последним функтором. Но это нехорошо, потому что нет надежного способа получить адрес перегруженного члена стандартного типа. Другими словами, вторая строка в приведенном выше тексте не гарантируется для компиляции.

Для дальнейшего использования я предпочитаю лямбды при вызове перегруженного члена:

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
...