C++ 编译时非侵入式结构到元组(或任何其他)类的转换

问题描述 投票:0回答:3

先决条件:
我无法获得提升。
我有第三方 C 标头,描述结构的内容,例如

typedef struct
{
   int int_value;
   char char_value;
   bool bool_value;
}
example_struct_t;

我无法对其进行任何更改。

目标:
我需要以自定义文本格式序列化该结构中的数据。

我计划制作按类型的序列化器,例如

SerializerBase, SerializerINT::SerializerBase
SerializerCHAR::SerializerBase
等。

并在一些模板类中使用它,(伪代码):

Serializer<example_struct_t = T>
{
   foreach_field_in<T> is field
   {
      if(field.type == typeof(int))
      {
         AddToResult(SerializerINT::Serialize(field.value));
      }
   }
}

或者一些不太“模板化”的东西(伪代码):

class SerializationSequence<example_struct_t = T>
{
   std::vector<SerializerBase> sequence;

   SerializationSequence()
   {
       sequence = GenerateMethodsSequenceForThisStruct<T>(); // Compile time
   }
}

C++ 有什么方法可以在编译时解析这个结构并制作一些东西,比如

std::tuple<int,char,bool>

c++ serialization reflection
3个回答
2
投票

C++ 反射提案可以轻松做到这一点。 它还没有用 C++ 编写。

可以通过多种方式获取 C++ 解析树。 这是相当极端的,涉及黑客攻击或使用自定义编译器。

最后,还有一些技巧涉及检测支架结构的空气性并使用

[]
进行拆包。 这可能是最实用的了。

基本思想是您可以在即时上下文中测试

T{a0, a1, a2}
是否合法。 您创建一个具有“通用”
template<class T>operator T()
的类型,并找到可以使用
{}
s 创建类型实例的最大数量。

然后你通过

解压
auto&& [b0, b1, b2] = t;
return std::make_tuple(b0,b1,b2);

并从结果元组中提取类型,并为每个计数提供自定义(“手写”)版本。

它需要一堆代码生成,具有最大的处理能力,它只能很好地处理 POD 类型(带有一些扩展)。 但该技术是当前 C++ 中最接近的技术。

这里有人使用这种方法。 我不知道他们是否做得好,他们使用的许可证等等;这只是其他人使用此技术的一个例子。


0
投票

OP 写道,使用 boost 是不可能的,但随后指出包含单个标头是可能的。 magic_get 又名 boost.pfr 是一个 1 头库,并且应该完全按照 OP 的要求:将一个简单的结构转换为一个元组。请参阅 github.com/apolukhin/magic_get


0
投票

根据 Yakk 的回答,这是一个独立的解决方案;它的“独创性”在于可以生成代码(通过 python)来测试最多 N 个属性。

#include <type_traits>
#include <tuple>
#include <cstdint>

////////////////////////////////////////////////////////////////////////////////////////////////////
template< class T, class ...Args >
inline constexpr bool is_brace_constructible_v = requires { T {std::declval<Args>()...}; };

struct any_type {  template<class T>   constexpr operator T(); };

template<class T, typename FUNCTION>
constexpr auto fields_call (T&& object, FUNCTION f)
{
    using type = std::decay_t<T>;
    using at   = any_type;

    /************************* PYTHON for code generation *************************
        N = 3;
        for i in reversed(range(1,N+1)):
           s = [];
           l = ",".join(["p{:d}".format(n) for n in range(1,i+1)]) ;
           s.append (("else " if i<N else "") + "if constexpr(is_brace_constructible_v<type,{:s}>)".format (",".join(['at']*i)));
           s.append ("{");
           s.append ("     auto&& [{:s}] = object;". format(l) );
           s.append ("     return f({:s});".format(l));
           s.append ("}");
           print ("\n".join(s));
     */

    // BEGIN GENERATED CODE
    if constexpr(is_brace_constructible_v<type,at,at,at>)
    {
         auto&& [p1,p2,p3] = object;
         return f(p1,p2,p3);
    }
    else if constexpr(is_brace_constructible_v<type,at,at>)
    {
         auto&& [p1,p2] = object;
         return f(p1,p2);
    }
    else if constexpr(is_brace_constructible_v<type,at>)
    {
         auto&& [p1] = object;
         return f(p1);
    }    // END GENERATED CODE
}

template<typename T>
struct to_tuple
{
    using type = decltype (fields_call (T{},  [] (auto&&...args)
    {
        return std::make_tuple (std::forward<decltype(args)>(args)...);
    }));
};

template<typename T>
using to_tuple_t = typename to_tuple<T>::type;

////////////////////////////////////////////////////////////////////////////////////////////////////
struct foo
{
    uint8_t  a;
    uint16_t b;
    uint32_t c;
};

static_assert (std::tuple_size_v <to_tuple_t<foo>> == 3);

static_assert (std::is_same_v <decltype(foo::a), std::tuple_element_t<0,to_tuple_t<foo>>> == true);
static_assert (std::is_same_v <decltype(foo::b), std::tuple_element_t<1,to_tuple_t<foo>>> == true);
static_assert (std::is_same_v <decltype(foo::c), std::tuple_element_t<2,to_tuple_t<foo>>> == true);

演示

请注意,还可以使用

fields_call
来迭代给定结构的所有属性:

template<class T, typename FUNCTION>
auto fields_iterate (T&& object, FUNCTION fct) noexcept
{
    fields_call (object,  [&] (auto&&...args) { ( fct(std::forward<decltype(args)>(args)), ...); });
}
© www.soinside.com 2019 - 2024. All rights reserved.