передача функций-членов в качестве параметров / c ++ - PullRequest
4 голосов
/ 19 мая 2011

Я хотел бы реализовать в c ++ класс b , где можно было бы выполнить какую-то итерацию через набор элементов, инкапсулирующий тип этого итератора. Нравится:

b_object.for_each_x_do(function_f);

так что function_f получит всех членов x и сделает что-нибудь. Допустим,

void function_f(x_member_type x){ cout << x << endl; }

Хорошо. Поэтому я пытаюсь добиться этого с помощью кода, подобного:

class b{
    int *x;
public:
    void foreach_x_do(void (*f)(int)){
            while(*x++)  // or any kind of iteration through x
                    f(*x);
    }
};

class a{
    b b_inst;
public:
    void f(int x) {  }     
    a(){
            b_inst.foreach_x_do(f); // by mistake it was b_inst.foreach_x_do(f)(), however this wasn't the point at all. 
    }
    ~a(){}
};

int main(){} 

Однако, я получаю эту ошибку, время компиляции:

fp.cpp: в конструкторе ‘a::a()’:
fp.cpp: 17: ошибка: отсутствует функция для вызова ‘b::foreach_x_do(<unresolved overloaded function type>)’
fp.cpp: 6: примечание: кандидаты: void b::foreach_x_do(void (*)(int))

Кто-нибудь может помочь заставить его скомпилировать?

Ответы [ 6 ]

2 голосов
/ 19 мая 2011

Как отметил @ steveo225, f в этом контексте имеет тип void (a::*)(int), а не void (*)(int). Существует два подхода к решению этой проблемы. Первый - сделать b::foreach_x_do шаблоном-функцией-членом, который принимает любой вызываемый тип:

class b {
    int* x;

public:
    b() : x() { }
    template<typename F>
    void foreach_x_do(F f) {
        while(*x++)
            f(*x);
    }
};

class a {
    b b_inst;

public:
    void f(int x) { }
    a() : b_inst() {
        b_inst.foreach_x_do(std::bind(&a::f, this, _1));
    }
};

Второй - сохранить b::foreach_x_do не-шаблон и заставить его принимать std::function<> вместо указателя функции:

class b {
    int* x;

public:
    b() : x() { }
    void foreach_x_do(std::function<void(int)> const& f) {
        while(*x++)
            f(*x);
    }
};

class a {
    b b_inst;

public:
    void f(int x) { }
    a() : b_inst() {
        b_inst.foreach_x_do(std::bind(&a::f, this, _1));
    }
};

В любом случае замените std::bind и std::function их аналогами boost::, если ваш компилятор слишком стар, чтобы поставляться с реализациями std:: или std::tr1::. Также обратите внимание, что если у вас есть компилятор C ++ 11, вы можете использовать лямбду вместо bind.

1 голос
/ 19 мая 2011

Функция for_each_x_do ожидает указатель функции, в то время как вы (пытаетесь) дать ей указатель на функцию-член.Два не одинаковы.Первый может быть вызван напрямую, а второй требует вызова экземпляра объекта.Я бы посоветовал вам использовать std::function или boost::function.Что-то вроде:

void for_each_x_do(function<void (int)> f) {
  // your code here
}

И затем использовать связыватель для создания объекта функции:

a(){
  b_inst.foreach_x_do(bind(&a::f, this, _1));     
}
1 голос
/ 19 мая 2011

Это должно быть просто:

b_inst.foreach_x_do(f);

Вам также нужно сделать f статическим, а не нестатическим методом члена, поскольку исходная подпись для вашей функции foreach_x_do предназначена для автономногоуказатель на функцию, а не указатель на функцию-член.То есть

static void f(int x) {  } 
0 голосов
/ 19 мая 2011

f() - это функция member - поэтому ее актуальность ограничена соответствующим объектом. Некоторые из этих решений пока не работают.

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

Второй метод четко объяснен в этом полезном FAQ , в частности о передаче функций-членов.

0 голосов
/ 19 мая 2011

Попробуйте:

class b{
int *x;
public:
void foreach_x_do(void (*f)(int)){
        while(*x++)  // or any kind of iteration through x
                (*f)(*x);
}

};

0 голосов
/ 19 мая 2011

В этой строке:

 b_inst.foreach_x_do(f)();

Удалить второй набор скобок;они вам не нужны.

 b_inst.foreach_x_do(f);

должно работать нормально.

...