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

boost-pfr是如何获取结构的字段名称的?

  •  2
  • TooTone  · 技术社区  · 1 年前

    In Boost 1.84(当前 in progress ):

    大新功能:字段名称反射。添加了新的constexpr boost::pfr::get_name<N、 T>()函数,返回一个std::string_view,其名称为聚合T的索引N处的字段。需要C++20。

    使用 latest version of pfr on github ,您可以编写如下代码

    #include <boost/pfr/core.hpp>
    #include <boost/pfr/core_name.hpp>
    
    struct S
    {
        int i = 1;
        double d = 2;
        std::string s = "three";
    };
    
    const S s;
    constexpr auto names = boost::pfr::names_as_array<S>();
    boost::pfr::for_each_field(
        s,
        [&names](const auto& field, std::size_t idx)
        { std::cout << idx << ": " << names[idx] << " = " << field << '\n'; });
    

    输出:

    0: i = 1
    1: d = 2
    2: s = three
    

    这是如何工作的?这 blog post 解释了如何重新调整聚合初始化的用途以获取字段,但获取字段名似乎很神奇!但我在三大编译器(最新的Visual C++、gcc 13.2和clang 16)上得到了上述输出。我在看代码时并不明智 core_name20_static.hpp

    1 回复  |  直到 1 年前
        1
  •  3
  •   Artyer    1 年前

    你可能很熟悉 boost::typeindex::type_id<T>().pretty_name() 或各种自动“枚举到字符串”。这些用途 __PRETTY_FUNCTION__ / __FUNCSIG__ 以获得“pretified”函数名(包括完整地写出模板参数)。使用它,我们可以获得模板参数的名称:

    template<typename T>
    void test() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
    
    template<auto V>
    void test() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
    
    int main() {
        test<std::string>();
        enum { a };
        test<a>();
    }
    
    // GCC output
    void test() [with T = std::__cxx11::basic_string<char>]
    void test() [with auto V = main::a]
    

    您可以删除相应的字符以获得所需的“名称”。

    在C++20之前,指针/引用非类型模板参数必须指向完整的对象。在C++20中,它们现在可以指向子对象。因此,您创建一个对象并指向它:

    struct S
    {
        int i = 1;
        double d = 2;
        std::string this_is_the_name_we_want = "three";
    };
    
    extern S fake_object;
    
    template<auto* P>
    void test() {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
    
    int main() {
        test<&fake_object.this_is_the_name_we_want>();
    }
    
    // GCC output
    void test() [with auto* P = (& fake_object.S::this_is_the_name_we_want)]
    

    (您可以使用与相同的方法获得对每个成员的引用 boost::pfr::for_each_field )