std::function in std::unordered_map, error C3867 非标准语法;使用“&”创建指向成员的指针

std::function in std::unordered_map, error C3867 non-standard syntax; use '&' to create a pointer to member

我尝试用地图调用一些 api

来替换 if/else

为什么初始化列表会抛出错误?

...
#include <functional>
#include <unordered_map>

class MyClass final : public Base
{
   std::string InfoInquiry(Class_1& request, Class_2& response);
   std::string ActivateDeactivate(Class_1& request, Class_2& response);
   ...
   using Callback = std::function<std::string(Class_1&, Class_2&)>;
   const std::unordered_map<std::string, Callback> m_ApiCalbacks{ //error C3867: 'MyClass ::InfoInquiry': non-standard syntax; use '&' to create a pointer to member
      {"INFO", InfoInquiry},
      {"ACTIVATE_DEACTIVATE", ActivateDeactivate},
      ...
   };
}

注意:static 在这种情况下是不允许的,因为它在 dll 中并且重新加载 dll 会遇到问题

错误状态,该怎么做。但它只适用于简单的静态函数。

class MyClass : public Base {
    static std::string InfoInquiry(Class_1& request, Class_2& response);
    static std::string ActivateDeactivate(Class_1& request, Class_2& response);

    using Callback = std::function<std::string(Class_1&, Class_2&)>;
    const std::unordered_map<std::string, Callback> m_ApiCalbacks {
        {"INFO", &MyClass::InfoInquiry},
        {"ACTIVATE_DEACTIVATE", &MyClass::ActivateDeactivate},
    };
};

因为m_ApiCalbacks是常量,使用静态成员函数是有意义的。

我赞成为此使用 pointers-to-membersstd::function 是有代价的(至少一个额外的间接寻址,即慢)。

类似这样的内容(为简洁起见进行了编辑):

#include <functional>
#include <map>
#include <iostream>

class MyClass
{
public:
    std::string InfoInquiry() { return "info!"; }
    std::string ActivateDeactivate() { return "activate!"; }
    using Callback = std::string (MyClass::*) ();
    const std::map<std::string, Callback> m_ApiCalbacks {
       {"INFO", &MyClass::InfoInquiry},
       {"ACTIVATE_DEACTIVATE", &MyClass::ActivateDeactivate}
    };
    std::string Call(std::string const& name) {
        auto it = m_ApiCalbacks.find(name);
        if (it == m_ApiCalbacks.end()) // optional check if name is valid
            return "???";
        return (this->*(it->second))();
    }
};

int main() {
    MyClass c;
    std::cout << c.Call("INFO") << "\n";
    std::cout << c.Call("ACTIVATE_DEACTIVATE") << "\n";
    std::cout << c.Call("X") << "\n";
}

附注:在某些 C++ 实现中,std::mapstd::unordered_map 快。检查确定。 (Live demo)

部分没有说明(除了某些回复)是您正在尝试调用成员函数,并且要求您有一个指针(或引用,或其他)到您正在调用的 class 实例。如果您愿意,您 可以 将其包装到您的地图中。在这种情况下,您不需要这样做,因为您的地图“存在于”class 中,因此您不必这样做,但如果您愿意,这里有一种方法可以做到。

我采用了 rustyx 的实现,并略微更改它以展示另一种实现方式,保留被调用方方法的原始签名。

#include <functional>
#include <map>
#include <iostream>

class MyClass
{
public:
    std::string InfoInquiry(Class_1& request, Class_2& response) { return "info!"; }
    std::string ActivateDeactivate(Class_1& request, Class_2& response) { return "activate!"; }
    using Callback = std::function<std::string(Class_1&, Class_2&)>;
    const std::map<std::string, Callback> m_ApiCalbacks {
       {"INFO", std::bind(&MyClass::InfoInquiry, this, std::placeholders::_1, std::placeholders::_2)},
       {"ACTIVATE_DEACTIVATE", std::bind(&MyClass::ActivateDeactivate, this, std::placeholders::_1, std::placeholders::_2)}
    };
    std::string Call(std::string const& name, Class_1& c1, Class_2& c2) {
        auto it = m_ApiCalbacks.find(name);
        if (it == m_ApiCalbacks.end()) // optional check if name is valid
            return "???";
        return (it->second)(c1, c2);
    }
};

int main() {
    MyClass c;
    Class_1 local_c1{};
    Class_2 local_c2{};
    std::cout << c.Call("INFO", local_c1, local_c2) << "\n";
    std::cout << c.Call("ACTIVATE_DEACTIVATE", local_c1, local_c2) << "\n";
    std::cout << c.Call("X", local_c1, local_c2) << "\n";
}

这保留了通过使用 std::bind 来调用具有任意参数的方法的能力,以创建具有您想要的签名的可调用函数,同时还保留指向您的实例的指针。但是,如果您曾在 class 的 外部 执行此操作,请确保您没有使用悬挂指针。在这里,使用 this 并且您的地图与您的 class 一样长,但如果您的 bind 目标是另一个 class,请确保它不指向对象当您尝试调用它时,它不再存在。