【问题标题】:C++ Use macros to define class member of a single classC++ 使用宏定义单个类的类成员
【发布时间】:2017-02-21 12:40:39
【问题描述】:

我正在尝试实现一个通用设置结构,以便在一个地方访问我的应用程序的所有设置。应用程序的每个模块都有自己的设置类/结构。我想在通用设置结构中定义一个具有每个模块设置类型的成员。为了方便起见,我想定义一个 REGISTER 宏,为每个模块设置创建一个新成员。

类似这样的:

struct Settings
{    
    // I know this is not working
    #define REGISTER_SETTINGS(settings) \
            settings _##settings = ##settings();
};

struct ServerSettings
{
    int port = 8080;
    string ip = "0.0.0.0";
};

REGISTER_SETTINGS(ServerSettings);

struct WindowSettings
{
    int width = 640;
    int height = 480;
    string title = "window";
};

REGISTER_SETTINGS(WindowSettings);

最后我的设置结构应该是这样的:

struct Settings
{   
    ServerSettings _ServerSettings = ServerSettings(); 
    WindowSettings _WindowSettings = WindowSettings();
};

我不知道如何在其中获得宏扩展。

【问题讨论】:

  • 在 C++ 中使用宏的一句话指南:不要
  • 您需要从宏中删除分号,对于一个
  • 为什么要在结构体中定义宏??
  • 您不能从结构定义外部向结构添加成员。

标签: c++ macros


【解决方案1】:

您应该避免使用宏。在我看来,它甚至没有 senseREGISTER_SETTINGS(settings),因为您是程序员,只需将这两行写入 Settings 结构,就可以了... 但是如果你仍然想要这样的函数,可以使用内联函数来编写它。

【讨论】:

    【解决方案2】:

    正如其他人所说,最好完全避免使用宏。

    但是,要回答所提出的问题......

    要声明具有其他struct 类型实例的成员的struct 类型,编译器必须已经看到这些包含类型的声明。因此,只需更改定义的顺序即可。

    struct ServerSettings
    {
        int port = 8080;
        string ip = "0.0.0.0";
    };
    
    struct WindowSettings
    {
        int width = 640;
        int height = 480;
        string title = "window";
    };
    
    struct Settings
    {    
    #define REGISTER_SETTINGS(settings) \
            settings _##settings = ##settings()
    
         REGISTER_SETTINGS(ServerSettings);
         REGISTER_SETTINGS(WindowSettings);
    
          // etc
    
    #undef REGISTER_SETTINGS
    };
    

    注意#undef 防止在struct Settings 的定义之外使用宏。

    但有一个关键问题。这将创建以下划线开头后跟大写字母的标识符。此类标识符由 C++ 标准保留,使用它们会导致您的代码具有未定义的行为。避免这种情况的一种方法是将宏更改为

    #define REGISTER_SETTINGS(settings) \
        settings a_##settings = ##settings()
    

    防止创建保留标识符。

    二、声明

     Type name = Type();
    

    基本上默认初始化name,因此在功能上等同于

     Type name;
    

    所以你可以进一步将宏简化为

    #define REGISTER_SETTINGS(settings) \
        settings a_##settings
    

    正如我一开始所说,最好完全避免使用宏。宏只是掩盖了这样做的事实;

    // definitions of ServerSettings and WindowSettings here
    
    struct Settings
    {    
         ServerSettings a_ServerSettings;     
         WindowSettings a_WindowSettings;
    };
    

    这比您尝试使用的宏的混淆更容易阅读。显然,您可以为Settings 的成员使用任何您喜欢的命名约定。

    【讨论】:

      【解决方案3】:

      你可以这样做:

      #define REGISTER_SETTINGS(settings)  \
              settings _##settings = settings(); 
      

      注意settings()之前没有'##'。

      但是:

      1. 正如 cmets 中已经指出的那样:最好不要使用宏。
      2. 这不会产生你所期望的结果,例如:

        struct Settings
        {   
             ServerSettings _ServerSettings = ServerSettings(); 
             WindowSettings _WindowSettings = WindowSettings();
        };
        

        但它会在调用宏的地方创建对象:

        struct Settings
        ...
        struct ServerSettings
        ...
        ServerSettings _ServerSettings = ServerSettings();
        
        struct WindowSettings
        ...
        WindowSettings _WindowSettings = WindowSettings();
        
      3. 我建议使用一些creational pattern,例如(抽象)工厂或工厂方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-14
        相关资源
        最近更新 更多