Как я могу передать функцию-член, где ожидается свободная функция?

Вопрос заключается в следующем: рассмотрим этот кусок кода:

#include <iostream>class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};

void function1(void (*function)(int, int))
{
function(1, 1);
}

void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}

int main (int argc, const char* argv[])
{
aClass a();

function1(&test);
function1(&aClass::aTest); // <-- How should I point to a's aClass::test function?

return 0;
}

Как я могу использовать a«s aClass::test в качестве аргумента function1? Я застрял в этом.

Я хотел бы получить доступ к члену класса.

86

Решение

Нет ничего плохого в использовании указателей на функции. Однако указатели на нестатические функции-члены не похожи на обычные указатели на функции: функции-члены должны вызываться для объекта, который передается в качестве неявного аргумента функции. Подпись вашей функции-члена выше, таким образом,

void (aClass::*)(int, int)

а не тип, который вы пытаетесь использовать

void (*)(int, int)

Один подход может состоять в том, чтобы сделать функцию-член static в этом случае он не требует вызова какого-либо объекта, и вы можете использовать его с типом void (*)(int, int),

Если вам нужен доступ к любому нестатическому члену вашего класса а также вам нужно придерживаться указателей функций, например, потому что функция является частью интерфейса C, ваш лучший вариант — всегда передавать void* к вашей функции с помощью указателей на функции и вызова вашего члена через функцию пересылки, которая получает объект из void* а затем вызывает функцию-член.

В правильном интерфейсе C ++ вы можете захотеть взглянуть на то, как ваша функция принимает шаблонный аргумент для объектов функции, использующих произвольные типы классов. Если использование шаблонного интерфейса нежелательно, вы должны использовать что-то вроде std::function<void(int, int)>: вы можете создать для них подходящий вызываемый функциональный объект, например, используя std::bind(),

Безопасные с точки зрения типов подходы с использованием аргумента шаблона для типа класса или подходящего std::function<...> предпочтительнее, чем использование void* интерфейс, поскольку они устраняют возможность ошибок из-за приведения к неправильному типу.

Чтобы уточнить, как использовать указатель на функцию для вызова функции-члена, вот пример:

// the function using the function pointers:
void somefunction(void (*fptr)(void*, int, int), void* context) {
fptr(context, 17, 42);
}

void non_member(void*, int i0, int i1) {
std::cout << "I don't need any context! i0=" << i0 << " i1=" << i1 << "\n";
}

struct foo {
void member(int i0, int i1) {
std::cout << "member function: this=" << this << " i0=" << i0 << " i1=" << i1 << "\n";
}
};

void forwarder(void* context, int i0, int i1) {
static_cast<foo*>(context)->member(i0, i1);
}

int main() {
somefunction(&non_member, 0);
foo object;
somefunction(&forwarder, &object);
}
102

Другие решения

@Pete Becker ответит хорошо, но вы также можете сделать это, не пройдя class экземпляр как явный параметр function1 в C ++ 11:

#include <functional>
using namespace std::placeholders;

void function1(std::function<void(int, int)> fun)
{
fun(1, 1);
}

int main (int argc, const char * argv[])
{
...

aClass a;
auto fp = std::bind(&aClass::test, a, _1, _2);
function1(fp);

return 0;
}
61

Указатель на функцию-член отличается от указателя на функцию. Чтобы использовать функцию-член через указатель, вам нужен указатель на нее (очевидно) и объект, к которому она будет применена. Поэтому соответствующая версия function1 было бы

void function1(void (aClass::*function)(int, int), aClass& a) {
(a.*function)(1, 1);
}

и назвать это:

aClass a; // note: no parentheses; with parentheses it's a function declaration
function1(&aClass::test, a);
38

С 2011 года, если вы можете изменить function1, сделайте так, вот так:

#include <functional>
#include <cstdio>

using namespace std;

class aClass
{
public:
void aTest(int a, int b)
{
printf("%d + %d = %d", a, b, a + b);
}
};

template <typename Callable>
void function1(Callable f)
{
f(1, 1);
}

void test(int a,int b)
{
printf("%d - %d = %d", a , b , a - b);
}

int main()
{
aClass obj;

// Free function
function1(&test);

// Bound member function
using namespace std::placeholders;
function1(std::bind(&aClass::aTest, obj, _1, _2));

// Lambda
function1([&](int a, int b) {
obj.aTest(a, b);
});
}

(живое демо)

Обратите внимание, что я исправил определение вашего сломанного объекта (aClass a(); объявляет функцию).

2

Я задал похожий вопрос (C ++ openframeworks передает void от других классов) но ответ, который я нашел, был более понятным, поэтому вот объяснение будущих записей:

проще использовать std :: function как в:

 void draw(int grid, std::function<void()> element)

а затем позвоните как:

 grid.draw(12, std::bind(&BarrettaClass::draw, a, std::placeholders::_1));

или даже проще:

  grid.draw(12, [&]{a.draw()});

где вы создаете лямбду, которая вызывает объект, захватывая его по ссылке

1

Вы можете перестать стучать головой Вот обертка для поддержки функции-члена существующий функции, принимающие в простом С функции в качестве аргументов. thread_local директива является ключом здесь.

http://cpp.sh/9jhk3

// Example program
#include <iostream>
#include <string>

using namespace std;

typedef int FooCooker_ (int);

// Existing function
extern "C" void cook_10_foo (FooCooker_ FooCooker) {
cout << "Cooking 10 Foo ..." << endl;
cout << "FooCooker:" << endl;
FooCooker (10);
}

struct Bar_ {
Bar_ (int Foo = 0) : Foo (Foo) {};
int cook (int Foo) {
cout << "This Bar got " << this->Foo << endl;
if (this->Foo >= Foo) {
this->Foo -= Foo;
cout << Foo << " cooked" << endl;
return Foo;
} else {
cout << "Can't cook " <<  Foo << endl;
return 0;
}
}
int Foo = 0;
};

// Each Bar_ object and a member function need to define
// their own wrapper with a global thread_local object ptr
// to be called as a plain C function.
thread_local static Bar_* BarPtr = NULL;
static int cook_in_Bar (int Foo) {
return BarPtr->cook (Foo);
}

thread_local static Bar_* Bar2Ptr = NULL;
static int cook_in_Bar2 (int Foo) {
return Bar2Ptr->cook (Foo);
}

int main () {
BarPtr = new Bar_ (20);
cook_10_foo (cook_in_Bar);

Bar2Ptr = new Bar_ (40);
cook_10_foo (cook_in_Bar2);

delete BarPtr;
delete Bar2Ptr;
return 0;
}

Пожалуйста, прокомментируйте любые проблемы с этим подходом.

Другие ответы не в состоянии назвать существующий гладкий C функции: http://cpp.sh/8exun

0

Я сделал функцию-член статической, и все работает:

#include <iostream>

class aClass
{
public:
static void aTest(int a, int b)
{
printf("%d + %d = %d\n", a, b, a + b);
}
};

void function1(int a,int b,void function(int, int))
{
function(a, b);
}

void test(int a,int b)
{
printf("%d - %d = %d\n", a , b , a - b);
}

int main (int argc, const char* argv[])
{
aClass a;

function1(10,12,test);
function1(10,12,a.aTest); // <-- How should I point to a's aClass::test function?

getchar();return 0;
}
0
По вопросам рекламы [email protected]