使用指向成员函数的指针作为 unordered_map 中的键

Using a pointer to a member function as a key in unordered_map

我有一个无序映射 std::unordered_map<void (MyClass::*)(), double> 用于存储调用函数后经过的时间。我收到一条错误消息

error: use of deleted function ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = void (MyClass::*)(); _Tp = double; _Hash = std::hash<void (MyClass::*)()>; _Pred = std::equal_to<void (MyClass::*)()>; _Alloc = std::allocator<std::pair<void (MyClass::* const)(), double> >]’

这是什么原因造成的,我该如何解决?有没有更好的方法来做我想做的事情?

std::unordered_map stores its data using some calculations involving std::hash 函数。正如 std::hash 的文档中所述,在“基本类型的标准特化”和“库类型的标准特化”小节下,std::hashvoid (MyClass::*)() 只能执行有限的类型不是其中之一,因为它的 non-static 和 non-static 方法指针不能在没有对象的情况下使用。

一个可能的解决方案是使用 std::string 作为键,当函数被调用时使用 __func__ 作为函数内部的键。

这是一个可行的解决方案:

#include <unordered_map>
#include <iostream>
#include <chrono>
#include <thread>

class MyClass
{
public:
    using FuncPtr = void (MyClass::*) ();
    using WrapperPtr = void (*) (MyClass&, void (MyClass::*) ());
    void func1() {
    }
    void insert(std::pair<WrapperPtr, unsigned long long> pair) {
        m_functionMap.insert(pair);
    }
    void printTime() {
        std::hash<WrapperPtr> hashKey;
        std::hash<unsigned long long> hashValue;
        for (auto itr{ begin(m_functionMap) }; itr != end(m_functionMap); ++itr) {
            std::cout << hashKey(itr->first) << " " << itr->second << std::endl;
        }
    }
private:
    std::unordered_multimap<WrapperPtr, unsigned long long> m_functionMap;
};

void methodWrapper(MyClass& myClass, MyClass::FuncPtr funcPtr) {
    myClass.insert({ &methodWrapper, std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count() });
    (myClass.*funcPtr)(); // Actual call.
}

int main()
{
    MyClass myObj;
    methodWrapper(myObj, &MyClass::func1);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    methodWrapper(myObj, &MyClass::func1);
    myObj.printTime();
}

为什么我们需要使用methodWrapper?为什么我们不能将 FuncPtr 作为键类型传递给 m_functionMap?因为 non-static 没有对象就不能使用方法指针。这就是 strange-looking 行的原因:

(myClass.*funcPtr)();

我认为静态方法解决方案更有意义:

#include <unordered_map>
#include <iostream>
#include <chrono>
#include <thread>

class MyClass
{
public:
    static void func1() {
        m_functionMap.insert({ &MyClass::func1, std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count() });
    }
    static void printTime() {
        std::hash<decltype(&MyClass::func1)> hashKey;
        std::hash<unsigned long long> hashValue;
        for (auto itr{ begin(m_functionMap) }; itr != end(m_functionMap); ++itr) {
            std::cout << hashKey(itr->first) << " " << itr->second << std::endl;
        }
    }
private:
    static std::unordered_multimap<decltype(&MyClass::func1), unsigned long long> m_functionMap;
};

std::unordered_multimap<decltype(&MyClass::func1), unsigned long long> MyClass::m_functionMap{};

int main()
{
    MyClass::func1();
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    MyClass::func1();
    MyClass::printTime();
}

总而言之,我的建议是使用 __func__