如何构建 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;
}}
};
我想为一组采用 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;
}}
};