C++ 中函数指针中的多态参数


是否可以

安全地在C++中的两个函数指针之间进行转换,因为参数是多态等价的,即(仅示例(

class Base {}
class A : Base {}
class B : Base {}
class C : Base {}
template<typename T, typename U>
using FPTR = void (*)(const T&, const U&);
using index = std::pair<std:type_info, std::type_info>;
std::unordered_map<index, FPTR<Base, Base>> func_map;
template<typename T, typename U>
register(FPTR<T,U> fptr) {
   // assert T and U are subclasses of Base
   func_map[index(typeid(T), typeid(U))] = fptr;
}
void call(const Base& first, const Base& second) {
   auto it = func_map.find(index(typeid(first), typeid(second)));
   if (it != func_map.end()) {
        (*it)(first, second)
   }
}
void func1(const A&, const C&) {}
// call these
register<A,C>(func1);
register<B,B>([](const B&, const B&) -> void {});

因此,当调用调用时,它会根据注册的类型 ID 解析要调用的函数,并且被调用的函数需要显式类型,从而有效地从基类型强制转换。

我的想法是这将在运行时导致错误,因为转换 wron 无法正确发生。我已经考虑过使用 lambda 函数来包装 fptr,但这会导致额外的间接调用,有没有办法在正确执行强制转换时避免这种情况,请注意我不能在调用中转换,因为我只能获取 typeid/type_info 并且不能将其与强制转换函数一起使用。

如果这不是问题,您可以通过额外的直接调用来完成(目标调用甚至可以在包装器中内联,具体取决于您的编译器和翻译单元的设置方式(。

像这样:

struct Base {}
// ...
template <typename T, typename U>
using FPTR = void (*)(const T&, const U&);
template <typename T, typename U, FPTR<T,U> fptr>
void WrapFPTR(const Base &a, const Base &b)
{
  fptr(static_cast<const T&>(a), static_cast<const U&>(b));
}

允许您在注册给定函数的每个站点上存储WrapFPTR<T,U,foo> FPTR<Base,Base> foo

如果确实需要任意函数指针,则需要存储一个多态闭包对象,其中包含指向该函数的具体类型的指针。

当前C++不包含复杂的co(ntra(方差概念。你可以改用静态映射吗?

#include <iostream>
class Base {};
class A : Base {};
class B : Base {};
class C : Base {};
template<typename T, typename U> using FPTR = void (*)(const T&, const U&);
// instead of allocating a run-time map, create a map on compiler's heap at compile-time
template<typename U, typename V> static FPTR<U const &, V const &> funcMap;
void nyan(A const &, A const &) { std::cout << "Nyan" << std::endl; }
void meow(B const &, B const &) { std::cout << "Meow" << std::endl; }
int main() {
    funcMap<A, A> = nyan;
    funcMap<B, B> = meow;
    funcMap<A, A>(A{}, A{});
}

最新更新