【问题标题】:Split a struct into a tuple [duplicate]将结构拆分为元组[重复]
【发布时间】:2018-02-24 15:06:46
【问题描述】:

问题很直接,我该如何生成:

std::tuple<float, int, double>

如果我知道类型:

struct Foo { float a; int b; double c; };

我怎样才能在两种转换中检索数据?

【问题讨论】:

  • C++ 语言本身并没有实现这种类型转换的功能。你必须自己做。
  • 正常的答案是你不能。 C++ 没有执行此操作所需的反射。当然,您可以添加自己的预处理器脚本来解析声明并生成元组。还有一些基于 UB 的增强功能不应该起作用,但无论如何都会起作用。
  • 你需要反思。您可以使用 magic_get 执行类似的操作,但它仅适用于 pod 类型。
  • @GuillaumeRacicot:感谢您提供指向 magic_get 的链接。我正在寻找那个。这是talk at CppCon,详细解释了它。
  • 所有用户:cmets 仅用于 on-topic 澄清帖子。他们不是为了我刚刚清理的那种争吵。不要重新开始讨论。

标签: c++ tuples metaprogramming


【解决方案1】:

您不能在 C++ 中执行此操作,因为它需要称为 reflection 的语言功能。

相反,“手动”构建元组或首先从一个元组开始。

或者,您可以使用 Python(或类似语言)构建一个脚本来预处理您的代码并自动生成结果转换。

【讨论】:

  • 我希望 C++17 甚至 C++20 有所改进。好吧,我想这很遗憾:)
  • 赞成最后一句话。有时我更喜欢 Python 而不是丑陋的元编程......
  • 确实如此。一个好的预构建步骤没有任何问题。我在一个文本文件中有一个“消息类型”及其逻辑字段的列表,Python 会为我“编译”成 C++ 类,因为它们需要所有丑陋的样板。很可爱。
【解决方案2】:

你可以写一个转换运算符。

struct Test {
    int a;
    float b;
    double c;

    explicit operator std::tuple<int, float, double>() const {
       return {a, b, c};
    }
};

然后,像这样使用它:

int main() {
    Test t{12, 3.2f, 4.5};
    std::tuple tt = t; 
}

Live example

【讨论】:

  • 但我不能写 std:get&lt;0&gt;(t); 这可能是所需的用例。
  • @Wyck 我不知道这是否是所需的语义。除非我没有正确理解这个问题,否则 OP 没有具体问这个问题。
【解决方案3】:

正如其他答案所说,在 C++14 中无法以通用方式执行此操作。

但是,C++17 中有一个使用结构化绑定的技巧:

template<typename T>
auto as_tuple_ref( T & t )
{
   auto &[a,b,c] = t;
   return std::tie(a,b,c);
}

struct Foo { float a; int b; double c; };

Foo bar;
int & b_ref = std::get<1>( as_tuple_ref(bar) );

此版本仅适用于具有 3 个成员的结构,但我相信通过一些时间和努力(以及一些 SFINAE),可以编写一个完全通用的解决方案(并且可能涉及大量复制粘贴)。

【讨论】:

    【解决方案4】:

    您可以手动完成。例如:

    #include <iostream>
    #include <tuple>
    
    using std::tuple;
    using std::cout;
    using std::endl;
    using std::get;
    
    struct Foo { float a; int b; double c; };
    
    int main()
    {
      auto tuple_foo = tuple<decltype(Foo::a), decltype(Foo::b), decltype(Foo::c)>{1.1f, 10, 100.001};
      cout << "<0>: " << get<0>(tuple_foo) << endl;
      cout << "<1>: " << get<1>(tuple_foo) << endl;
      cout << "<2>: " << get<2>(tuple_foo) << endl;
    }
    

    【讨论】:

    • 那么auto 有什么意义呢?你为什么不直接tuple&lt;...&gt; f = {...}
    • @user202729:你也可以这样做。有些人痴迷于auto ;)
    • @user202729 • 我采纳了同事 Herb Sutter 的建议:herbsutter.com/2013/08/12/…
    • @Eljay:这是对短语“陪审团还没有决定是否推荐这个批发商,因为我们还在尝试”
    • @Eljay:很遗憾听到这个消息。 AAA 是一种糟糕的编码方式。
    【解决方案5】:

    基于这些成员名称,即:第一个成员称为a,第二个称为b,第三个称为c。您可以定义以下结构模板 member_type&lt;&gt; 来获取每个单独成员的类型:

    template<typename T>
    struct member_type : T {
        using a_t = decltype(T::a);   
        using b_t = decltype(T::b);   
        using c_t = decltype(T::c);   
    };
    

    使用此别名模板tuple_splitter&lt;&gt;,您可以从struct 中定义一个具有此类成员(命名为abc)的元组:

    template<typename T>
    using tuple_splitter = std::tuple
                     <
                        typename member_type<T>::a_t,
                        typename member_type<T>::b_t,
                        typename member_type<T>::c_t
                     >;
    

    那么,为你的Foo

    tuple_splitter<Foo> foo_tuple;
    

    foo_tuple 将具有 std::tuple&lt;float, int, double&gt; 类型。

    如果你现在定义一个新的structBar,为:

    struct Bar { int a; char b; float c; };
    

    然后:

    tuple_splitter<Bar> bar_tuple;
    

    bar_tuple 的类型为 std::tuple&lt;int, char, float&gt;

    【讨论】:

      【解决方案6】:

      使用 std::tie 甚至更容易:

      struct foo
      {
          int value1;
          int value2;
          string str;
      };
      
      void main()
      {
          std::tuple<int, int, string> a{ 1, 1, "Hello " };
          foo b;
          std::tie(b.value1, b.value2, b.str) = a;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-04
        • 2018-11-22
        • 1970-01-01
        • 2014-09-06
        • 2016-07-03
        • 1970-01-01
        • 1970-01-01
        • 2019-09-21
        相关资源
        最近更新 更多