简体   繁体   中英

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

I have a unordered map std::unordered_map<void (MyClass::*)(), double> used to store the time that has elapsed since a function has been called. I'm getting an error saying that

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> >]'

What is causing this, and how do I fix it? Is there a better way to do what I trying to do?

std::unordered_map stores its data using some calculations involving std::hash function. As described in the documentation for std::hash , under subsections "Standard specializations for basic types" and "Standard specializations for library types", there are only limited types that std::hash can perform on and void (MyClass::*)() is not one of them since its non-static and a non-static method pointer can not be used without an object.

One possible solution is to use std::string as the key and when a function is called use the __func__ as the key inside the function.

This is a working solution:

#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();
}

Why do we need to use methodWrapper ? Why can't we just pass FuncPtr as key type to the m_functionMap ? Because non-static method pointers can not be used without an object. That's the reason for this strange-looking line:

(myClass.*funcPtr)();

and the static method solution which I belive makes more sense:

#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();
}

In conclusion my suggestion is using __func__ .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM