在阅读(并希望学习)有关成员函数指针,vtables,constexpr及其限制,并集等内容之后,我已经到了需要C ++专家帮助的地步:
我必须使用带有许多类似虚拟方法的库。这些方法可能具有不同的签名,因此至少我必须为每种方法提供一组不同的调用参数。通常,每种方法都需要不同的处理方式。
我尝试使用switch语句在不同的处理情况之间进行选择。切换条件应该是vtable中的方法offset,我认为是
从其他线程,例如strings are used as case-expressions,我了解到,要将vtable偏移量用作大小写表达式,它必须是 constexpr 。由于 constexpr 的许多限制,我创建了一个联合以转换成员函数指针,并提供了一个 constexpr 运算符以将联合值返回为整数。
所有这些都导致了以下代码,该代码几乎但不完全不同于我的意图:
// Compiled with g++ (Ubuntu 4.8.5-4ubuntu8~14.04.2) 4.8.5
// -std=c++03 and -std=c++1y give the same results !
#include <iostream>
// method library:
struct funcLib
{
virtual void a() {}
virtual void b(const double &_dVal) {}
virtual void c(const double &_dVal, int &iVal) {}
};
// typedef to handle member function pointers with different signatures:
typedef void (funcLib::*T_Function)();
// union for type-conversion:
union funcID {
T_Function m_funcPtr;
uintptr_t m_funcID;
explicit constexpr funcID( T_Function _funcPtr ) : m_funcPtr(_funcPtr) {}
constexpr operator uintptr_t() const { return m_funcID; }
};
int main()
{
uintptr_t i = funcID((T_Function)&funcLib::a);
uintptr_t j = funcID((T_Function)&funcLib::c);
uintptr_t k = funcID((T_Function)&funcLib::b);
std::cout << i << " " << j << " " << k << std::endl; // results "1 9 5" which seems to be OK!!
// Uncommenting the switch statement gives the error:
// ../src/Test.cpp:37:44: in constexpr expansion of 'funcID(&funcLib::a).funcID::operator uintptr_t()'
// ../src/Test.cpp:37:44: error: accessing 'funcID::m_funcID' member instead of initialized 'funcID::m_funcPtr' member in constant expression
//
// switch (i) {
// case funcID((T_Function)&funcLib::a) : /* some handling */ break;
// case funcID((T_Function)&funcLib::b) : /* some handling */ break;
// case funcID((T_Function)&funcLib::c) : /* some handling */ break;
// }
return 0;
}
前3行确实为我提供了方法的vtable偏移量,这证明了类型转换是合理的,但是在case-expressions中使用相同的调用会导致编译器错误。
有人可以看看并给我一些提示吗?
添加: 这是一些伪代码,希望可以阐明我的意图:
// Own method to centralize the calls into the library
double T_MyClass::callLibraryMethod(T_FunctionID _funcID, T_CallParams _callParams)
{
double result;
switch (_funcID) {
case &Lib::methodA: result = Lib::methodA(_callParams); break;
case &Lib::methodB: result = Lib::methodB(_callParams); break;
case &Lib::methodC: result = Lib::methodC(_callParams); break;
...
}
return result;
}
...
// Usage:
T_CallParams ParamsForMethodA, ParamsForMethodB;
double dResult;
...
dResult = callLibraryMethod(&Lib::methodA, ParamsForMethodA);
...
dResult = callLibraryMethod(&Lib::methodB, ParamsForMethodB);