我有一个模板化的基类,用作伪状态机类型的对象。它有一个主要方法if not x
(在错误检查之后)逐步检查一个枚举(作为模板参数之一提供),并针对其处于任何状态运行一个处理程序。问题是我必须使用该指针引用Progress_State()
数组,该数组是派生类函数指针的数组(即Event_Handler
= Event_Handlers[i]
)。
函数定义在一个单独的XX.cpp文件中,该文件包括XX.h文件(定义了模板类)。但是,由于所有函数都是模板函数,因此我最终得到了未解析的符号。经过研究,我发现编译使用模板类的文件时,编译器需要访问模板化函数定义,因此我将XX.cpp重命名为XX.tpp,并在#include“ XX .tpp”位于“ XX.h”底部。它以前没有任何问题地进行过编译,但是只是这一更改导致了编译错误。最值得注意的是,在尝试调用存储的函数指针的行中,出现“表达式必须具有指针类型”错误。
Templates.h
Derived_Class::*
Templates.tpp
/*
* 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"
我怀疑这种情况正在发生,因为“ this”指针实际上指向某种派生类,但是我找不到解决它的方法。
以下是我尝试过的其他操作:
以下几行会产生以下错误:
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 ...
}
错误:“表达式必须具有(指向指针的)功能
预期的功能是仅调用注册的处理函数(单独设置)并逐步执行该顺序。
预先感谢
答案 0 :(得分:1)
我在您的代码中看到以下问题:
您尝试使用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();
}
答案 1 :(得分:0)
您似乎正在搜索std::invoke
。这是MSVC已经使用了一段时间处理可调用对象的功能。 (_INVOKE在标准中可用)。
auto return value = std::invoke(func, arg1, arg2, ...);
对于您的情况,您可以这样称呼它:
auto errorCode = std::invoke(EventHandlers[Current_State], *this);