简体   繁体   English

使用C++模板编程提取任意结构的字段类型

[英]using C++ template programming to extract the field types of an arbitrary structure

If I define a struct with arbitrary data types like:如果我定义一个具有任意数据类型的结构,例如:

struct custom_type {
    int a;
    float b;
    char c; 
    float *d; // etc...
};

Is there a common pattern using template programming (C++) to extract the field types of this struct and map them to some type-specific code handler at compile time ?是否有使用模板编程 (C++) 来提取此结构的字段类型并在编译时将它们映射到某些特定于类型的代码处理程序的通用模式?

Some context: I'm creating an api that allows for clients to define their own arbitrary custom types, and still allow those to integrate with the underlying system I have for managing and introspecting these types, doing automated memory management and other housekeeping.一些上下文:我正在创建一个 api,它允许客户端定义他们自己的任意自定义类型,并且仍然允许它们与我用于管理和内省这些类型、执行自动内存管理和其他内务的底层系统集成。

The "wrapping" template or other mechanism will allow this integration without the underlying system knowing anything about the header file that defines the custom type. “包装”模板或其他机制将允许这种集成,而底层系统无需了解有关定义自定义类型的头文件的任何信息。 From the client's point of view, the code accesses the struct in the normal way, but the template allows generic handling of each field in the struct.从客户端的角度来看,代码以正常方式访问结构,但模板允许对结构中的每个字段进行通用处理。

Thanks.谢谢。

The behavior you describe is called reflection .您描述的行为称为反射 The C++ language features which support this feature are very limited (yet).支持此功能的 C++ 语言功能非常有限(目前)。 However, with some tricks it is possible to achieve some level of reflection.但是,通过一些技巧,可以实现某种程度的反射。

One example is Boost.PFR (Precise and Flat Reflection) by Antony Polukhin.一个例子是 Antony Polukhin 的 Boost.PFR(精确和平面反射)。 PFR is an official boost library since December 2020 (boost 1.75.0), but according to its documentation it is a自 2020 年 12 月(boost 1.75.0)以来,PFR 是官方 boost 库,但根据其文档,它是一个

header only library that does not depend on Boost.不依赖于 Boost 的仅头文件库。

Here is one example from the README :这是自述文件中的一个示例

#include <iostream>
#include <string>

#include "boost/pfr.hpp"

struct some_person {
    std::string name;
    unsigned birth_year;
};

int main() {
    some_person val{"Edgar Allan Poe", 1809};

    std::cout << boost::pfr::get<0>(val)                // No macro!
        << " was born in " << boost::pfr::get<1>(val);  // Works with any aggregate initializables!

    std::cout << boost::pfr::io(val);                   // Outputs: {"Edgar Allan Poe", 1809}
}

In the chapter on Limitations and Configuration , the docs state that at least C++14 is required, but at least C++17 is recommended.限制和配置一章中,文档指出至少需要 C++14,但建议至少使用 C++17。 One important requirement is that一个重要的要求是

T must be aggregate initializable without empty base classes T 必须是可聚合初始化的,没有空基类

Some underlying techniques are explained in a recorded CppCon 2016 talk with the title "C++14 Reflections Without Macros, Markup nor External Tooling.." .录制的 CppCon 2016 演讲中解释了一些基础技术,其标题为“C++14 Reflections without Macros, Markup or External Tooling..”

No, that's not possible using templates or any other features in the standard C++ language. 不,使用标准C ++语言中的模板或任何其他功能是不可能的。 Such a feature is known as introspection or reflection. 这种特征被称为内省或反思。 If you search using those terms, you'll find some external tools that can provide such information at build time (eg clang); 如果您使用这些术语进行搜索,您会发现一些可以在构建时提供此类信息的外部工具(例如clang); after generating it you can run custom tools performing code generation. 生成后,您可以运行执行代码生成的自定义工具。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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