Использование указателя «this» в определении функции класса шаблона - выражение должно иметь (указатель на) тип функции - PullRequest
0 голосов
/ 31 декабря 2018

У меня есть шаблонный базовый класс, который я использую в качестве объекта типа псевдо-конечного автомата.У него есть основной метод Progress_State(), который (после проверки ошибок) выполняет перечисление (предоставляется как один из аргументов шаблона) и запускает обработчик для любого состояния, в котором он находится. Проблема в том, что мне нужно использовать указатель thisдля ссылки на массив Event_Handler, который является массивом указателей на функции производного класса (т. е. Event_Handlers[i] = Derived_Class::*).

Определения функций находились в отдельном файле XX.cpp, который включал XXФайл .h (где были определены классы шаблонов).Однако, так как все функции были шаблонными функциями, я получил неразрешенные символы.После некоторых исследований я обнаружил, что определения шаблонных функций должны быть доступны компилятору при компиляции файлов, использующих класс шаблона, и поэтому я переименовал XX.cpp в XX.tpp и вставил #include "XX.tpp "в нижней части" XX.h. "Раньше он компилировался без проблем, но только это изменение вызывало ошибки компиляции.В частности, я получаю сообщение об ошибке «выражение должно иметь тип указателя» в строке, где я пытаюсь вызвать указатель сохраненной функции.

Templates.h

/*
 * derived_class = is the derived class type, used for correctly 
 * using the function pointers
 * event_type = the enum that we're using as "sequencer"
 * max_events = the "max_XX" enum, used to set our handler array size
 */
template< derived_class, event_type, max_events >
Class Base{

// Set up the typedef for the derived class function pointer
   typedef int(derived_class::*PFN)(void);

public:
    // ....
   int Progress_State();
    // ....

private:
   // ....
   PFN           Event_Handlers[Num_Events];
   event_type    Current_State;
   // ....       

};

// Bring in the templated function definitions
#include "Templates.tpp"

Templates.tpp

template< derived_class, event_type, max_events >
int Base::Progress_State(){

   // Various error checking stuff, including whether or not we're
   // at the end of the sequence, or if we have a null handler

   // If no errors, continue.
   // FYI: 0 indicates no errors

   if( 0 == this->*Event_Handlers[Current_State]() ){ // <--* error happens here

      // Step sequence -- some funkiness here to allow for incrementing
      // of the sequence without overloading the ++ operator for every
      // enum we intend to track, while also protecting against 
      // overruns

      Current_State = static_cast<event_type>( 
          (static_cast<int>(Current_Event) + 1) % max_events
       );
   }

   // ... do other stuff as needed ...
}

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

Вот еще несколько вещей, которые я пробовал:

Следующие строки генерируют следующую ошибку:

OK == this->*Event_Handlers[Current_State]();
OK == *Event_Handlers[Current_State]();
(*this).*Event_Handlers[Current_State]();

error:"выражение должно иметь (указатель на) функцию

Ожидаемая функциональность будет состоять в том, чтобы просто вызвать зарегистрированную функцию-обработчик (устанавливается отдельно) и пошагово выполнить последовательность.

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Я вижу следующую проблему в вашем коде:

Вы пытаетесь вызвать функцию-член производного класса внутри базового класса с помощью this, который не является совместимым типом указателя.Сначала необходимо привести тип указателя к производному классу.Вы «знаете», что это указатель на производный класс, так как здесь вы используете шаблон CRTP.https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

В упрощенном примере вызов выглядит примерно так:

template < typename Derived >
class Base
{
    public:
        using PTR_T = void(Derived::*)();
        PTR_T ptr;

        Base( PTR_T _ptr ) : ptr {_ptr}{}

        void Call()
        { 
        // the important thing here is the cast to the derived type of "this"
            (((Derived*)this)->*ptr) ();
        }
};

class Derived: public Base< Derived >
{
    public:
        void F() { std::cout << "Hello" << std::endl; }

        Derived():Base{ &Derived::F } {}
};  

int main()
{   
    Derived d;
    d.Call();
}
0 голосов
/ 31 декабря 2018

Похоже, вы ищете std::invoke.Это функциональность, которую MSVC уже использует некоторое время для работы с вызываемыми объектами.(_INVOKE прежде чем доступно в стандарте).

 auto return value = std::invoke(func, arg1, arg2, ...);

Для вашего случая вы можете назвать это как:

 auto errorCode = std::invoke(EventHandlers[Current_State], *this); 
...