Проблемы с адаптацией функций-членов в Фениксе

Я использую BOOST_PHOENIX_ADAPT_FUNCTION все время в духе. Я хотел бы иметь возможность адаптировать функции-члены по той же причине. Тем не менее, я получаю ошибки компиляции, если я делаю что-то вроде этого:

struct A { int foo(int i) { return 5*i; }};

BOOST_PHOENIX_ADAPT_FUNCTION(int, AFoo, &A::foo, 2)

Есть ли простой способ адаптировать функцию-член? Обратите внимание, что я не могу просто сохранить выражение привязки в auto потому что я на VC2008. Как получается, что это не просто работает, как в bind а также function?

Спасибо,

Майк

2 ответа

Решение

BOOST_PHOENIX_ADAPT_FUNCTION(RETURN,LAZY_NAME,FUNC,N)это действительно просто. Это просто создает функтор с шаблонным operator() это возвращает RETURN и имеет N параметры шаблона. В своем теле это просто вызывает FUNC(PARAMETERS...), Но &A::foo не вызывается напрямую, поэтому возникает ваша ошибка. Ты можешь использовать:

BOOST_PHOENIX_ADAPT_FUNCTION(int,AFoo,boost::mem_fn(&A::foo),2)

Бег на Колиру

#include <iostream>
#include <boost/phoenix.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/mem_fn.hpp>

struct A {
    A(int f) : f_(f) {}

    int foo(int i) {
        return f_*i;
    }
  private: 
    int f_;
};

BOOST_PHOENIX_ADAPT_FUNCTION(int,AFoo,boost::mem_fn(&A::foo),2)

int main() {
    using namespace boost::phoenix;
    using namespace boost::phoenix::arg_names;

    A instance(5);
    std::cout << AFoo(arg1,arg2)(&instance, 2) << std::endl;
}

Начиная с самого простого:

Как получилось, что он не просто работает как в связывании и функционировании?

Поскольку макрос предназначен для функций, а не функций-членов. Функции указателя на член сильно отличаются от указателей на функции, так что это конец пути.


В вашем примере A::foo на самом деле не нужно быть методом экземпляра (нестатическая функция-член), поэтому просто добавьте static (и неявный параметр) и будет сделано:

struct A {
    static int foo(int i) {
        return 5*i;
    }
};

BOOST_PHOENIX_ADAPT_FUNCTION(int, AFoo, A::foo, 1)

Предположим, однако, что вы хотели иметь нестатическую функцию-член. По этой причине давайте добавим небольшое состояние к A тип:

struct A {
    A(int f) : f_(f) {}
    int foo(int i) { return f_*i; }
  private: 
    int f_;
};

Phoenix предлагает следующие подходы для создания ленивых актеров, вызывающих функции-члены:

  1. использовать ->* оператор. Это приводит к немного неясному синтаксису:

    A instance(9);
    
    int direct    = (arg1->*&A::foo)(arg2)
                        (&instance, 7); // direct == 63
    
  2. В качестве альтернативы, вы можете использовать bind выражение (примечание: boost::phoenix::bind здесь!), что может быть именно тем, что вы искали:

    int with_bind = bind(&A::foo, arg1, arg2)
                        (&instance, 7);
    

Теперь, конечно, вы можете назначить ленивый функтор переменной. В этом отношении я могу только рекомендовать BOOST_AUTO:

BOOST_AUTO(afoo, (arg1->*&A::foo)(arg2));
return afoo(&instance, 2);

Который работает как шарм.

Полный пример C++03

Посмотреть это в прямом эфире на Coliru

struct A {
    A(int f) : f_(f) {}

    int foo(int i) {
        return f_*i;
    }
  private: 
    int f_;
};

#include <boost/phoenix.hpp>
#include <boost/phoenix/function.hpp>
#include <cassert>

int main() {
    using namespace boost::phoenix;
    using namespace boost::phoenix::arg_names;

    A instance(9);

    int direct    = (arg1->*&A::foo)(arg2)
                        (&instance, 7);

    int with_bind = bind(&A::foo, arg1, arg2)
                        (&instance, 7);

    assert(direct == with_bind);

    BOOST_AUTO(afoo, (arg1->*&A::foo)(arg2));

    return afoo(&instance, 2);
}
Другие вопросы по тегам