如何构建 std::map 到为派生 class 重载的函数

How to build std::map to functions overloaded for derived class

我想为一组采用 Base 对象的函数构建一个 std::map,同时还为特定的 Derived class 重载。如果函数没有超载,设置如下:

#include <functional> 

bool func_1( const Base& );
bool func_2( const Base& );

std::map< std::string, std::function< bool (const Base&) > > funcMap = {
    { "a", func_1 },
    { "b", func_2 }
};

这没有问题。但是现在如果我有一个 class Derived 继承自 Base :

class Derived : public Base {
    ...
}

并添加“func_1”的重载版本:

bool func_1( const Base& );
bool func_2( const Base& );
bool func_1( const Derived& );
std::map< std::string, std::function< bool (const Base&) > > funcMap = {
    { "a", func_1 },
    { "b", func_2 }
};

它将不再编译,给出错误:

error: could not convert ‘{{"a", func_1},{"b", func_2}}’ from ‘<brace-enclosed initializer list>’ to ‘std::map<std::__cxx11::basic_string<char>, std::function<bool(const Base&)> >’

天真地我会假设因为地图是用模板参数定义的 std::function< bool (const Base&) > 它能够正确地将 func_1 对象匹配到采用 Base 参数,但显然情况并非如此。有没有办法解决或规避这个问题?

您必须将函数指针转换为您需要的类型,编译器将select为您转换为的类型进行正确的重载:

{"a", (bool(*)(const Base&))func_1 },

这不是很干净,函数指针语法可能会令人困惑,但这是使该代码正常工作所需要的

我没有意识到 c-cast 即使没有实际匹配签名的函数也会编译,所以这个解决方案更安全:

{"a", static_cast<bool(*)(const Base&)>(func_1)}

此外,在我们讨论的同时,您还可以使用 lambda:

{"a", [](const Base & o) { return func_1(o); } }

您可以使用包装函数来调用需要传递给它的派生实例的平面函数。包装器只是执行 dynamic_cast(或 static_cast)并调用所需的函数。

bool func_1( const Base& );
bool func_2( const Base& );
bool func_3( const Derived& );

bool func_3_wrapper(const Base &b) {
    const Base *pB = &b;
    const Derived *pD = dynamic_cast<D*>(pB);
    return pD ? func_3(*pD) : return false;
}

std::map< std::string, std::function< bool (const Base&) > > funcMap = {
    { "a", func_1 },
    { "b", func_2 },
    { "c", func_3_wrapper }
};

或者,由于您的映射值是 std::function 个实例,您可以执行 lambda。

std::map< std::string, std::function< bool (const Base&) > > funcMap = {
    { "a", func_1 },
    { "b", func_2 },
    { "c", [](const Base &b)->bool {
             auto pD = dynamic_cast<const Derived*>(&b);
             return pD ? func_3(*pD) : false;
           }}
};