【问题标题】:Loop over POD members循环 POD 成员
【发布时间】:2013-06-27 23:52:59
【问题描述】:

我想知道如何正确循环普通旧数据类型的成员,以便获取有关它们的一些类型信息。那就是:

struct my_pod
{
    int a;
    double b;
};

template<typename POD>
void loopOverPOD()
{
    for_each(POD, member) // The magic part
    {
        // member::type should be for my_pod int, then double
        typename member::type i;
        // member::size_of should be equal to sizeof(int) then sizeof(double)
        // Trivial if we can have member::type information.
        int size = member::size_of;
        // member::offset_of should be equal to 0, then sizeof(int)
        // Trivial if we can have member::size_of information.
        int offset = member::offset_of;
    }
}

据我所知,在 C++ 中,如果不对模板进行一些棘手的操作,我们就无法进行简单的类型自省。但是在这里,我找不到使用模板的具体解决方案,即使实际上使用宏也是如此。问题更多是关于我,而不是关于解决方案的存在。 :-)

我不一定要求一个不会侵入的解决方案。

提前致谢。

【问题讨论】:

  • 这是不可能的
  • 您是否考虑过使用std::tuple 而不是POD 类型。
  • @CaptainObvlious 如果与 POD 模板参数一起使用,std::tuple 是否是 POD?
  • 反射不是 C++ 语言的一部分。但它可以用外部工具来完成,参见例如Boost Reflect 库 (bytemaster.github.io/boost_reflect/…)。
  • 您要解决的真正问题是什么?在某些语言中,您可以通过反射解决的许多问题在 C++ 中以不同方式解决。

标签: c++ templates introspection


【解决方案1】:

您可以使用 boost.fusions ADAPT_STRUCT 将您的 POD 转换为序列,然后使用 fusions for_each 将函数对象应用于每个成员。这是非侵入式的,您的 POD 类型将保持为 POD。

好消息是您甚至可以将 ADAPT_STRUCT 宏放在与结构定义分开的(头文件)文件中,并且只在需要迭代的代码中使用它们。

另一方面,这个宏需要重复提及成员的类型和名称。我想在某些时候融合将使用 C++11 特性来摆脱这种冗余(再次提到类型)。同时,可以创建一个宏来声明结构和 ADAP_STRUCT 部分。

【讨论】:

  • 正是我需要的!非常感谢。即使宏被说成是邪恶的,对于 POD 类型,它们似乎也没有那么邪恶。
【解决方案2】:

如果您使用 C++14 和更高版本,您可以使用 Boost.Precise and Flat Reflection (https://github.com/apolukhin/magic_get/) 循环您的 POD 并使用 boost::typeindex::type_id_runtime(field) 打印类型:

#include <iostream>
#include <boost/pfr/precise.hpp>
#include <boost/pfr/flat.hpp>
#include <boost/type_index.hpp>

struct my_pod
{
    int a;
    double b;
};

struct my_struct
{
    char c;
    my_pod pod;
};

int main() {
    my_pod val{1, 2.5};

    my_struct var{'a', 1, 2.5};

    std::cout <<  "Flat:\n";
    boost::pfr::flat_for_each_field(var, [](const auto& field, std::size_t idx) {
        std::cout << idx << ": " << boost::typeindex::type_id_runtime(field) << "; value: " << field << '\n';
    });

    std::cout <<  "\nNot Flat:\n";
    boost::pfr::for_each_field(var, [](const auto& field, std::size_t idx) {
        using namespace boost::pfr::ops;
        std::cout << idx << ": " << boost::typeindex::type_id_runtime(field) << "; value: " << field << '\n';
    });
}

此示例的输出:

Flat:
0: char; value: a
1: int; value: 1
2: double; value: 2.5

Not Flat:
0: char; value: a
1: my_pod; value: {1, 2.5}

虽然我不确定在这种情况下如何抵消......

【讨论】:

    【解决方案3】:

    C++ 没有遍历结构成员的构造。

    但是存在一个标准类型 std::tuple,您可以使用模板在编译时对其元素进行递归迭代。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-07
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 2020-08-15
      • 2015-08-02
      相关资源
      最近更新 更多