代码之家  ›  专栏  ›  技术社区  ›  mardy

获取类中成员函数的构建时唯一ID

c++
  •  2
  • mardy  · 技术社区  · 6 月前

    我需要为类的每个成员函数获取一个唯一的ID,可以将其用作模板参数(这意味着它必须在编译时静态确定)。我的第一个想法是在类中使用函数的索引,但据我所知,没有办法获得它。所以,我试图在类中用成员函数的偏移量,但我不知道如何获得它:

    #include <iostream>
    #include <typeinfo>
    
    class MyClass {
        template <typename F>
        size_t getUniqueId(F f) {
            return ...something unique, maybe based on f's offset?...
        }
    
    public:
        void method1(bool) {
            std::cout << "My ID is " << getUniqueId(&MyClass::method1) << '\n';
        }
    
        void method2(int) {
            std::cout << "My ID is " << getUniqueId(&MyClass::method2) << '\n';
        }
    
        void method3(bool) {
            std::cout << "My ID is " << getUniqueId(&MyClass::method3) << '\n';
        }
    };
    int main()
    {
        MyClass a;
        a.method1(true);
        a.method2(1);
        a.method3(true);
    }
    

    我尝试这样实现getUniqueId():

        template <typename F>
        size_t getUniqueId(F f) {
            return typeid(f).hash_code();
        }
    

    但是(毫不奇怪)这不起作用,因为它对方法1和方法3返回相同的值,因为它们的签名是相同的。

    我想我将不得不求助于使用预处理器宏(我可以直接使用 __LINE__ 从方法中获取唯一ID),但更可取的是干净的C++解决方案。

    1 回复  |  直到 6 月前
        1
  •  3
  •   joost jasper    6 月前

    这是一个在C++17中对我有效的选项。

    
    #include <iostream>
    #include <typeinfo>
    
    class MyClass {
        template<auto F>
        struct FunctionTag {};
    
        template<auto F>
        static std::size_t getUniqueId() {
            return typeid(FunctionTag<F>).hash_code();
        }
    
    public:
        void method1(bool) {
            std::cout << "My ID is "
                      << getUniqueId<&MyClass::method1>()
                      << '\n';
        }
    
        void method2(int) {
            std::cout << "My ID is "
                      << getUniqueId<&MyClass::method2>()
                      << '\n';
        }
    
        void method3(bool) {
            std::cout << "My ID is "
                      << getUniqueId<&MyClass::method3>()
                      << '\n';
        }
    };
    int main() { MyClass a; a.method1(true); a.method2(1); a.method3(true); }
    
        2
  •  0
  •   GKxx    6 月前

    指向成员函数的指针可以用作模板参数。

    std::source_location 自C++20以来,编译器定义的宏,如 __PRETTY_FUNCTION__ (适用于GCC和LLVM)以及 __FUNCSIG__ (适用于MSVC)在C++20之前。模板参数(如果有的话)将包含在“漂亮名称”中。

    这些使我们找到了如下解决方案:

    // This demonstrates that both the member function's fully qualified name and its type can be obtained.
    // You can adjust the contents of this string or encode it to a unique integer on your own.
    template <auto MemFunPtr, typename Ty = decltype(MemFunPtr)>
    constexpr auto getUniqueId() {
    #if __cplusplus > 201703L
        return std::string_view{std::source_location::current().function_name()};
    #else
        return std::string_view{__PRETTY_FUNCTION__};
    #endif
    }
    

    用途:

    constexpr auto id = getUniqueId<&Class::method1>();
    

    编译器资源管理器上的演示: https://godbolt.org/z/Kxa94jT1o