You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

借助CRTP获取C++20重载方法类型并存入元组

在C++20中通过CRTP将重载成员函数指针存入元组

问题描述

我希望在C++20的CRTP模板基类中,自动将派生类中所有名为f的重载成员函数指针存入std::tuple,例如:

template<typename CRTP>
struct Template {
    // 此处写法错误,需要元编程技巧实现
    static inline constexpr std::tuple t{&CRTP::f...};
};

struct S : Template<S> {
    void f(int) { }
    void f(bool) { }
};

期望元组t包含&S::f(int)和&S::f(bool)两个成员函数指针,且该模板能被多个不同派生类复用:

struct S1 : Template<S1> {
    void f(int) { }
    void f(bool) { }
};

struct S2 : Template<S2> {
    void f(std::string) { }
    void f(double) { }
    void f(std::vector<unsigned>) {}
    struct SomeOtherType {};
    void f(SomeOtherType) {}
};

解决方案说明

在标准C20中,编译器无法自动枚举类的所有重载成员函数签名,因此无法直接通过&CRTP::f...生成元组。我们可以通过让派生类显式声明重载签名列表的方式实现需求,这是标准C中最可靠的方案,同时保留模板的复用性。

完整实现代码

#include <tuple>
#include <vector>
#include <string>

// CRTP基类:接受派生类类型和f的重载签名列表
template<typename CRTP, typename... Signatures>
struct Template {
private:
    // 辅助模板:将签名转换为成员函数指针类型
    template<typename Signature>
    struct GetMemberPtr;

    template<typename Ret, typename... Args>
    struct GetMemberPtr<Ret(Args...)> {
        using type = Ret(CRTP::*)(Args...);
    };

    // 辅助函数:生成对应签名的成员函数指针
    template<typename Ret, typename... Args>
    static constexpr auto get_ptr(Ret(CRTP::*)(Args...)) {
        return &CRTP::f;
    }

public:
    // 生成包含所有重载成员函数指针的元组
    static inline constexpr auto t = std::tuple{
        get_ptr(static_cast<typename GetMemberPtr<Signatures>::type>(nullptr))...
    };
};

// 示例派生类1:显式声明f的重载签名
struct S1 : Template<S1, void(int), void(bool)> {
    void f(int) { }
    void f(bool) { }
};

// 示例派生类2:显式声明f的重载签名
struct S2 : Template<S2, void(std::string), void(double), void(std::vector<unsigned>), void(S2::SomeOtherType)> {
    struct SomeOtherType {};
    void f(std::string) { }
    void f(double) { }
    void f(std::vector<unsigned>) {}
    void f(SomeOtherType) {}
};

// 验证代码
int main() {
    // 验证元组大小符合重载数量
    static_assert(std::tuple_size_v<decltype(S1::t)> == 2);
    static_assert(std::tuple_size_v<decltype(S2::t)> == 4);
    
    // 验证成员函数指针类型匹配
    using S1Tuple = decltype(S1::t);
    static_assert(std::is_same_v<std::tuple_element_t<0, S1Tuple>, void(S1::*)(int)>);
    static_assert(std::is_same_v<std::tuple_element_t<1, S1Tuple>, void(S1::*)(bool)>);
}

进阶方案(使用第三方库自动收集)

如果允许使用第三方元编程库(如Boost.Mp11),可以实现自动收集重载签名的功能,无需派生类显式声明。核心思路是利用库的元编程工具检测所有重载的存在并收集签名,再生成对应的成员函数指针元组。

总结

  • 标准C++20中,最可靠的方案是让派生类显式声明重载签名列表,基类根据签名生成成员函数指针元组。
  • 若需要完全自动收集,需借助第三方元编程库或编译器扩展。

内容的提问来源于stack exchange,提问作者K. Koovalsky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 21:15:53