【问题标题】:C++ nested macros?C++ 嵌套宏?
【发布时间】:2009-11-12 09:07:17
【问题描述】:

在 C++ 中,有什么方法可以在类中定义嵌套的宏/常量,以类似于嵌套 typedef 的方式,或实现类似功能的方法?动机通常是模板使用宏。

class SomeClass
{
public:
    #define SomeConstant 123
};

int x=SomeClass::SomeConstant;

当然,静态 const 成员可以完成这项工作,但这些是物理变量,而我正在寻找一种简单的类似宏的行为。

【问题讨论】:

    标签: c++ macros nested


    【解决方案1】:

    你不能用宏做你想做的事。宏没有作用域的概念。

    但是对于简单的 int 值,你可以用枚举做你想做的事情。

    class SomeClass
    {
    public:
        enum {
            SomeConstant=123
            };
    };
    
    int x=SomeClass::SomeConstant;
    

    该值的完全范围名称,但不占用空间,即使在调试版本中也是如此 - 如果您愿意,您无法获取其地址。

    【讨论】:

    • +1 用于使用枚举作为常量。我因“滥用”枚举而受到热议,但我认为我不会这样做。
    【解决方案2】:

    就地声明和定义的常量值正是您在这里所需要的:编译器可以并且将完全优化它们,因此它们最终与首先使用#define 完全相同,但具有以下好处严格的范围界定。

    class SomeClass {
      public:
       static const int someValue = 10;
    };
    

    这不会占用任何额外空间 - 没有分配内存来存储“someValue”。您可以证明这一点:如果您尝试将“someValue”用作真实对象(即您尝试获取它的地址),那么链接器会告诉您它是未定义的。

    【讨论】:

    • 严格来说,如果您使用 static const 变量,还有一个细节:您必须在某处有一个 const int SomeClass::someValue; 定义(仅一次,但仅当您使用该成员时)或者您依赖未定义的行为。我知道这实际上不是问题,如果没有真正使用,链接器仍然可以丢弃存储,并且几乎忽略了该规则(Stroustrup 认为这是一个“错误功能”),但它们是规则。 C++03 9.4.2/4 (stackoverflow.com/questions/370283/…)
    • 非常正确:我偶尔会发现,在将“someValue”传递给需要模板化引用的东西(例如测试工具)时,编译器想要获取 someValue 的地址,因此需要一个定义。但是,解决方法是使用一元加号运算符,因此在我的情况下,我将执行 ASSERT_EQUALS(+SomeClass::someValue, expr());
    【解决方案3】:

    宏完全忽略范围 - 它们在 C++ 编译之前被扩展。你就是不能那样做。

    使用 static const 通常会导致没有分配变量 - 编译器将其视为常量。

    【讨论】:

      【解决方案4】:

      宏预处理器通常不知道语言上下文;因此他们不知道什么是“类”使“嵌套在类中”一开始就没有意义。

      对于你想要的,要么使用静态常量,要么使用全名(假设预处理器允许在宏名称中使用冒号,这不是 100% 确定的)——尽管它不允许你在派生类上继承常量:

      #define SomeClass::SomeConstant 123
      

      【讨论】:

      • 在混合模板时使用全名(如果允许)将无济于事
      • ':' 在宏名称中不允许
      【解决方案5】:

      您可以使用模板来做到这一点:

      模板 类 SomeClass { 上市: void outputConstant() { cout

      但这并不是您想要的,因为您必须将类的实例声明为:

      int main(int argc, char *argv) { SomeClass myInstance; }

      我知道其他人已经解释了有关宏的部分,但请允许我补充:#define 由预处理器处理,而不是编译器。在标准中有一个称为“翻译阶段”的部分,它更详细地解释了这一点,但对于您的问题,关键是宏在类甚至编译之前就被评估,并且 #define 发生的范围是未知的。

      这方面的权威书籍(在编译阶段使用模板编程)是Modern C++ Design: Generic Programming and Design Patterns Applied, by Andrei Alexandrescu

      【讨论】:

        【解决方案6】:

        我不明白您反对使用静态常量。 它不会影响你的类的大小,编译器会优化以实现你认为你会从宏中得到什么。

        【讨论】:

          【解决方案7】:

          “静态成员是物理变量”。

          有什么反对的?反对这一点的唯一原因是内存使用。但是由于成员是静态的,因此内存只会被预期的内容占用一次。

          相反,使用宏,竞争将出现在二进制文件中的每个使用位置

          编辑: 如果变量是整数类型,小于指针,最好在类声明中定义常量。然后优化编译器可以内联调用代码中的值,就像宏一样。

          【讨论】:

          • 嗯。对于静态,地址将出现在二进制文件中的每个使用位置。所以如果它是我们正在谈论的一个字节......
          • 如果是char(或其他小的整数类型),您可以在类声明中定义它,它会再次内联。
          猜你喜欢
          • 2013-03-13
          • 2021-08-23
          • 2013-12-03
          • 1970-01-01
          • 1970-01-01
          • 2018-01-27
          • 2019-11-25
          • 1970-01-01
          • 2015-09-15
          相关资源
          最近更新 更多