【问题标题】:C++ macro function or dynamic member nameC++ 宏函数或动态成员名称
【发布时间】:2023-03-30 01:28:01
【问题描述】:

我有以下结构:

struct myHandler
{
  bool test1;
  bool test2;
  ...
  bool test400;
};

其中有大约 400 个测试值。所以目前我有以下功能:

static inline void DoSomething(myHandler& hdler, int test, bool passed)
{
  #define SETTEST(a,b,c) case b: a.test##b=c;

  switch (test)
  {
    SETTEST(hdler, 1, passed)
    SETTEST(hdler, 2, passed)
    ...
    SETTEST(hdler, 400, passed)
  }

  #undef SETTEST
};

我显然想摆脱重复的代码,因为有很多测试。所以我尝试了以下两种选择: 选项1:

static inline void DoSomething(myHandler& hdler, int test, bool passed)
{
  #define SETTEST(a,b,index,c) if(index==b) a.test##b=c;

  for(i = 1; i <= 400; ++i)
  {
    SETTEST(hdler, test, i, passed)
  }

  #undef SETTEST
};

显然,这不会编译,因为当它使用 ## 连接时,它需要字面上的“测试”。不知道如何或是否可以解决这个问题。

选项2:

template<typename FUNCTION>
inline void setTest(FUNCTION f) {
  for (int i = 1; i <= 5; ++i) {
    f(i);
  }
};

static inline void DoSomething(myHandler& hdler, int test, bool passed
{
  setTest([&](const int testNum) { 
    if(test == testNum) {
      hdler.test##testNum = passed;
    }
  });
};

显然 option2 也不会编译,我不知道如何使用某种动态形式访问结构的成员。现在,对实际结构进行了一些更改,可以轻松解决这个问题,但是修改结构不是一种选择,因为它是通过其他一些方法形成的,这只是描述我的问题的示例代码。我只想知道是否有一种方法可以做我错过的我想要实现的目标(不修改结构)。真的,我倾向于选项 2,但是从我所阅读的内容来看,无法动态连接以访问成员。任何帮助表示赞赏。

【问题讨论】:

  • 创建 2 种方法将丑陋的结构转换为 bitset/array/vector
  • 最好的选择是摆脱这个怪物并使用矢量。如果出于某种原因必须使用此结构,请使用 boost::preprocessor 库来消除重复。
  • myLittleVector[indexing] = isMagic;
  • 克罗姆。我的小向量。下一步是什么?卡雷熊?
  • @n.m.这种结构可能是有原因的。实际上,我正在研究硬件(远程,通过以太网访问)使用类似的东西的项目..但我们使用了一个带有开放数组的结构..

标签: c++ c++11 macros


【解决方案1】:

Boost PP再次闪耀。

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>

#define SET_TEST(z, n, data) \
    case n: hdler.BOOST_PP_CAT(test, n) = passed; break;
//             Note : was the break missing here? ^^^^^^

switch (test)
{
    BOOST_PP_REPEAT_FROM_TO(1, 400, SET_TEST, ~)
}

#undef SET_TEST

哦——你需要一个自定义的 Boost.PP 版本,所以它可以增加到 400 而不是默认的 256 :)

不认真...如果可以,请使用数组。

【讨论】:

    【解决方案2】:

    为什么不这样做:

    struct myHandler {
       bool test[400] = {};
    };
    

    PS。不,您尝试做的事情是不可能的,因为您正在尝试混合代码预处理或编译时间和执行时间。有些人可能会考虑递归模板,但同样,您也不能这样做,原因与您不能在模板中这样做一样。

    通过 char* 访问 struct 可以做到最好(和最坏)的努力。任何代码审查员都会用你的头骨制作一个酒杯。 具体来说,这是一个反模式(通常):

    myHandler s {};
    unsigned char* p = reinterpret_cast<unsigned char*>(&s);
    
    int index_value = 200;
    int n = 0;
    // sets index_value-th element to true.
    std::generate(p, p+sizeof(s), [&n,=](){ return (++n)==index_value; })
    //                    your "array" starts with 1^^^        
    

    如果bool 不等于 char.. 或者如果您需要更大的类型,那就有点花哨了。 generate 只会增加 1。但是您可以通过任何可能的方式遍历数组。

    【讨论】:

    • 这不是答案 - 这是一个问题!
    • @4386427 不,这是一个反问形式的答案。事实上,这是的答案。
    • @4386427 it; 被称为修辞问题。顺便说一句,为什么不总是用英语标记问题。它还用于“表示愤慨、轻微的惊讶或不耐烦”。这里两者都有一点,因为我在它后面使用了裸不定式从句。 (注意:英语不是我的母语)
    • @BoundaryImposition - 好吧,我不同意。这回答了这个问题。它提出了一种可能根本不相关的替代方法。问题的基础是结构是原样的。我们不知道 OP 是否可以更改结构。无论如何,OP 似乎并不关心这个问题,因为 OP 没有回答 cmets 中的问题。
    • @arias_JC OP 可能想知道这个人在 15 年前试图在不同的情况下(通过函数调用)解决这个 xy 问题,主要是出于无知。我可以保证不需要这样的代码,不花费时间来解决,并且通常被认为是设计代码的坏方法。您可以做的最好的事情是将我的结构和您的结构放入一个联合中并通过索引访问字段。那是正式的UB。如果 OP 愿意解释这段代码解决的 y 问题,我们可能会提供 x 的解决方案,这是现实的。
    【解决方案3】:

    我认为您的问题在这里没有简单的解决方案,但您可以尝试最佳答案here

    它讨论了是否可以遍历结构的成员(这在 C++ 中是不可能的),并提供了使用 Boost 的替代方法,如果您愿意的话。

    【讨论】:

    • boost 只是 C++ 的一个库.. 有一些方法可以遍历存储,实际上,如果要完全放弃结构,他们可以使用 std::tuple.. 但通常只需要元组具有不同类型的“字段”,具有相同类型,我们将使用数组\向量\列表>只要存在编程语言,结构(又名记录)和数组的定义几乎是不同的。
    • 是的,我知道它是一个库,只是以一般的方式引用它,而不会从别人的答案中获取太多。不过,我对看到一种遍历结构成员的方法非常感兴趣。
    • 我在工作中的项目中遇到了这样的问题.. 原因之一:我们必须自动生成在各个领域执行 hton\ntoh 的代码。结果我们不得不使用一个解析器程序来为我们做这件事。它生成的代码使用指针来洗牌结构,但步幅是由解析器而不是手动计算的。解析器只是获取带有结构声明的头文件,并为找到的每个结构生成带有函数(实际上是序列化类的方法)的文件
    • 对于这个问题,OP 是否可以使结构在内存中连续,允许它们以这种方式迭代?不过,这可能不是最安全的方法。
    • 好吧,它的字段大小相同.. 所以它是连续的。他的结构具有与数组相同的标准布局。也许在 SPARC 上不会,Solaris 编译器是否将 bool 视为 int?实际上,如果平台不这么认为,则有编译器特定的方法可以强制连续。 #pragma pack 在 VC 或 GCC 的情况下。填充实际上是可预测的,我们的解析器已将其考虑在内,精心设计的结构也不会有间隙。
    【解决方案4】:

    您无法编写几行代码来访问结构的各个成员。

    宏和模板将在编译时解析,因此您不能编写类似宏的函数来在运行时访问成员。

    所以,如果你真的被这样的结构卡住了,你必须编写一个包装器来隐藏结构相当丑陋的性质。编写包装器仍然需要很多行,但是一旦完成,代码的其他部分就会更加简单。

    它可能看起来像:

    #include <iostream>
    #include <array>
    using namespace std;
    
    struct myHandler
    {
      bool test1;
      bool test2;
      // ..
      bool test400;
    };
    
    struct myHandlerWrapper
    {
        myHandlerWrapper(myHandler& mh)
        {
            h[0] = &mh.test1;
            h[1] = &mh.test2;
                // .. 
            h[399] = &mh.test400;
        }
    
        bool& operator[](size_t i)  // This gives the easy access to members using simple indexing
        {
            return *h[i];
        }
    
        private:
        array<bool*, 400> h;
    };
    
    int main() {
        myHandler mh;
        myHandlerWrapper handler(mh);
    
        handler[0] = false;  // Access members using simple indexing via the wrapper
        handler[1] = true;
    
        cout << (handler[0] ? "true" : "false") << endl;
        cout << (handler[1] ? "true" : "false") << endl;
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-16
      • 2022-01-08
      • 2018-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多