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

时间:2018-03-13 13:13:15

标签: c++ lambda casting polymorphism function-pointers

是否可以安全地在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 {});

因此,在调用call时,它会根据已注册的typeid解析要调用的函数,并且被调用的函数会期望显式类型,从基类型中有效地进行转换。

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

2 个答案:

答案 0 :(得分:2)

如果这不是问题,你可以通过额外的直接调用来实现(目标调用甚至可以在包装器中嵌入,具体取决于你的编译器以及如何设置翻译单元。)

类似的东西:

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>的{​​{1}}。

如果你真的需要一个任意的函数指针,你需要存储一个多态闭包对象,并指向该函数的具体类型。

答案 1 :(得分:0)

当前的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{});
}