C ++使用宏来定义单个类的类成员

时间:2017-02-21 12:40:40

标签: c++ macros

我正在尝试实现一般设置结构,以便在一个位置访问我的应用程序的所有设置。应用程序的每个模块都有自己的设置类/结构。我想在常规设置结构中定义一个具有每个模块设置类型的成员。为了简化操作,我想定义一个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();
};

我不知道如何在那里进行宏扩展。

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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成员使用任何命名约定。

答案 2 :(得分:0)

你可以这样做:

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

请注意不要' ##'在settings()之前。

可是:

  1. 正如评论中已经指出的那样:更好地使用宏。
  2. 这不会产生您的期望,例如:

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

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

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