好吧,如果您正在寻找一种可移植的方式,我可以提供以下内容,即 C++ 编译器 must support。进一步讨论here。简而言之,它利用了根据 14.7.2p8 在显式模板实例化中绕过访问检查规则的事实:
14.7.2p8 通常的访问检查规则不适用于用于指定显式实例化的名称。 [注意:特别是,函数声明器中使用的模板参数和名称(包括参数类型、返回类型和异常规范)可能是通常无法访问的私有类型或对象,并且模板可能是成员模板或成员函数通常无法访问。]
它几乎做了你想做的事;唯一需要注意的是,根据 14.2,模板声明不能在函数范围内:
模板声明只能作为命名空间或类范围声明出现
这可能会破坏问题的精神,尽管它的措辞方式。
我不知道有什么方法可以将模板结构引入函数范围,但如果有类似的技巧,这可以 100% 完成你想要的。
////////////////////////////////////////////////////////////////////////////////////////
//// The template classes can unfortunately not be declared inside extractMultAdd ()
////////////////////////////////////////////////////////////////////////////////////////
#define ROB_PRIVATE_MEMBER_INST(CLASS, TYPE, MEMBER) \
template<typename T> \
struct CLASS##_##MEMBER##_rob_tag { \
typedef T CLASS::*type; \
friend type get(CLASS##_##MEMBER##_rob_tag); \
}; \
template<typename Tag, typename Tag::type M> \
struct CLASS##_##MEMBER##_rob_private \
{ \
friend typename Tag::type get(Tag) { return M; } \
}; \
template struct CLASS##_##MEMBER##_rob_private< \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>; \
#define ROB_PRIVATE_MEMBER_INST_FN(CLASS, TYPE, MEMBER) \
template<typename T> \
struct CLASS##_##MEMBER##_rob_tag { \
typedef T type; \
friend type get(CLASS##_##MEMBER##_rob_tag); \
}; \
template<typename Tag, typename Tag::type M> \
struct CLASS##_##MEMBER##_rob_private \
{ \
friend typename Tag::type get(Tag) { return M; } \
}; \
template struct CLASS##_##MEMBER##_rob_private< \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>; \
#define ROB_PRIVATE_MEMBER_ACCESS(CLASS, INSTANCE, TYPE, MEMBER) \
(INSTANCE.*get(CLASS##_##MEMBER##_rob_tag<TYPE>())) \
////////////////////////////////////////////////////////////////////////////////////////
//// Actually use the macros
////////////////////////////////////////////////////////////////////////////////////////
ROB_PRIVATE_MEMBER_INST(MultAdd, int, x);
ROB_PRIVATE_MEMBER_INST(MultAdd, int, y);
ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(MultAdd::*)(), add);
ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(MultAdd::*)(), multiply);
////////////////////////////////////////////////////////////////////////////////////////
//ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(__thiscall *)(), add);
int extractMultAdd(void* math)
{
// No need to pass as void*
MultAdd *pMA(reinterpret_cast<MultAdd*>(math));
// ROB_PRIVATE_MEMBER_INST(MultAdd, int, x); // Note that unfortunately this isn't possible
// The 4 values, retrieved in a portable way
int robbed_x = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int, x);
int robbed_y = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int, y);
int robbed_add = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int(MultAdd::*)(), add)(); // Note we're calling function with ()
int robbed_mul = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int(MultAdd::*)(), multiply)(); // Note we're calling function with ()
return 0;
}
忽略朋友声明警告并滚动到输出:
Run example
当然,“只写在 extractMultAdd() 函数中”可能会为这种语义欺骗留下一些空间:
int extractMultAdd(void* math)
{
return extractMultAdd_impl(math);
}
// structs
int extractMultAdd_impl(void* math)
{
// original code ...
} // <== Original brace :)