Идиома Именованного Параметра с использованием указателя на закрытый метод класса

Я застрял с ошибкой компиляции C ++, когда делал что-то, что, вероятно, не совсем «обычное».
Чтобы упростить задачу, я просто переписал механизм, который пытаюсь использовать, чтобы его было легче читать, и проверил, что у меня возникла та же проблема.

Прежде всего, вот код:

test.h // —— C ++ —

template <typename MODULE> class item;

template <typename MODULE>
class init {
public:
typedef int (MODULE::*funcPtr)(int);
private:
funcPtr m_fp;
public:
init& has_funcPtr(funcPtr fp) { m_fp = fp;}
init() {}
virtual ~init() {}
private:
friend class item<MODULE>;
};

template <typename MODULE>
class item {
public:
typedef int (MODULE::*funcPtr)(int);
private:
funcPtr m_fp;
public:
item(init<MODULE> params) : m_fp(params.m_fp) {}
virtual ~item() {}
};

class user {
public:
typedef init<user>::funcPtr funcPtr;
private:
// Method CB
int func1(int i);
// Item member
item<user> m_item;
public:
user();
virtual ~user();
};

test.cpp // —— C ++ —

#include "test.h"
user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {}

int user::func1(int i) {return 1;}

и вот ошибка:

/test.cpp:5:59: error: invalid use of non-static member function
user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {
^

Поэтому я не уверен, что это лучший способ добиться того, чего я хочу (вероятно, нет, в любом случае, если у вас есть другие предложения, которые они очень приветствуют), но сейчас моя цель — заставить его работать или понять, почему он не может работать. так что я чему-то научился из этого!

Основная идея заключается в том, что:

  • класс «item» может быть инициализирован с помощью именованного параметра idiom с использованием метода «has_funcPtr» класса «init», присоединенного к его конструктору, например:&function_name)».
  • класс «пользователь» может хранить указатель на свой приватный метод «func1» как закрытый член своего приватного члена типа «item».

Таким образом, когда вызывается конкретный метод объекта «item» (для простоты я не включаю эту длинную часть здесь, поскольку она не имеет отношения к ошибке, а просто описывает цель этого фрагмента кода) этот метод может делать вещи и вызывать закрытый метод своего родительского объекта «пользователь» через этот указатель на функцию (надеюсь, это достаточно ясно …).

Теперь я думаю, что есть проблема с порядком инициализации объектов, но я не уверен, где и как это исправить.
В частности, я подумал, что поскольку метод «func1» не работает ни с одним членом класса «пользователь», его ссылка может быть использована непосредственно в списке инициализации для инициализации объекта «init» и передачи его в «элемент» «объект.

Спасибо всем заранее

1

Решение

this->func1 не формирует указатель на функцию-член. Должно выглядеть &user::func1 если вы в user учебный класс.

4

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

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

Короче говоря, очень важно отметить две вещи:

  1. Указатель на нестатическую функцию-член класса можно рассматривать как просто смещение, а не как «абсолютный адрес» (http://www.codeguru.com/cpp/cpp/article.php/c17401/C-Tutorial-PointertoMember-Function.htm). Это означает, что вы не можете получить доступ к этой функции (это просто смещение) без предварительного указания указателя экземпляра. Если у вас есть указатель экземпляра, с этим «указателем смещения» вы можете вызвать этот метод, используя:

    (object_ptr->*method_ptr)(parameters_here)

    Лучше было бы использовать макрос #define, так как этот синтаксис действительно подвержен ошибкам и сложен для чтения (https://isocpp.org/wiki/faq/pointers-to-members):

    #define CALL_MEMBER_FN(ptrToObject,ptrToMember) ((ptrToObject)->*(ptrToMember))

    а затем использовать его как:

    CALL_MEMBER_FN(object_ptr, method_ptr)(parameters_here)

  2. Следуя первому пункту, если вы хотите, чтобы вложенный класс мог вызывать метод верхнего класса по указателю на него, вам также нужно передать указатель экземпляра верхнего класса для доступа к этой функции. В моем случае, так как я хотел иметь возможность решать в каждом конкретном случае, должен ли этот метод вызываться или нет, я использовал Идиому Именованных Параметров (ниже обратите внимание, что func2 не зарегистрирован, например).

Наконец, вот исправленный код, который работает (проверен):

— C ++ —— test.h

#include <iostream>

template <typename MODULE> class item;

template <typename MODULE>
class init {
public:
typedef int  (MODULE::*funcPtr)(int);
typedef bool (MODULE::*func2Ptr)(bool);
private:
funcPtr  m_fp;
func2Ptr m_fp2;
MODULE* m_dad;
public:
init& has_funcPtr(funcPtr fp) { m_fp = fp; return *this;}
init& has_func2Ptr(func2Ptr fp2) { m_fp2 = fp2; return *this;}
init(MODULE* dad) : m_dad(dad) { std::cout << "init constructor called\n"; }
~init() {}
private:
friend class item<MODULE>;
};

template <typename MODULE>
class item {
public:
typedef int  (MODULE::*funcPtr)(int);
typedef bool (MODULE::*func2Ptr)(bool);
private:
funcPtr  m_fp;
func2Ptr m_fp2;
MODULE*  m_dad;
public:
item(init<MODULE> params) :
m_fp(params.m_fp),
m_fp2(params.m_fp2),
m_dad(params.m_dad)
{
std::cout << "item constructor called\n";
}
~item() {}
// Method invoked externally
int callback() {
std::cout << "item class method callback invoked\n";
// In the real case here do general stuff
if(m_fp) {
int i = (m_dad->*m_fp)(1); // call member function through its pointer
return i;
} else {
std::cout << "callback not registered\n";
return 0;
}
}
// Method invoked externally
bool callback2() {
std::cout << "items class method callback2 invoked\n";
// In the real case here do general stuff
if(m_fp2) {
bool b = (m_dad->*m_fp2)(true); // call member function through its pointer
return b;
} else {
std::cout << "callback2 not registered\n";
return false;
}
}
};

class user {
public:
typedef init<user>::funcPtr funcPtr;
private:
// Methods that optionally add more functionalities to the 2 callbacks
int  func1(int i);
bool func2(bool b);
public:
// Item member
item<user> m_item;
public:
user();
~user();
};

— C ++ —— test.cpp

#include "test.h"
user::user() : m_item(init<user>(this).has_funcPtr(&user::func1) ) {
std::cout << "user constructor called\n";
}

int user::func1(int i) {return i;}
bool user::func2(bool b) {return b;} // func2 won't be registeredint main() {
user* u = new user();
// Test callbacks
int i = u->m_item.callback();
bool b = u->m_item.callback2();
std::cout << "main is printing i=" << i << " and b=" << b << "\n";
std::cout << "expected results are i=1 and b=0\n" << "END\n";
return 0;
}

ВЫХОД:

init constructor called
item constructor called
user constructor called
item class method callback invoked
items class method callback2 invoked
callback2 not registered
main is printing i=1 and b=0
expected results are i=1 and b=0
END
0

По вопросам рекламы [email protected]