我正在尝试实现一般设置结构,以便在一个位置访问我的应用程序的所有设置。应用程序的每个模块都有自己的设置类/结构。我想在常规设置结构中定义一个具有每个模块设置类型的成员。为了简化操作,我想定义一个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();
};
我不知道如何在那里进行宏扩展。
答案 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()
之前。
可是:
这不会产生您的期望,例如:
struct Settings
{
ServerSettings _ServerSettings = ServerSettings();
WindowSettings _WindowSettings = WindowSettings();
};
但它会在调用宏的地方创建对象:
struct Settings
...
struct ServerSettings
...
ServerSettings _ServerSettings = ServerSettings();
struct WindowSettings
...
WindowSettings _WindowSettings = WindowSettings();
我建议使用一些creational pattern之类的(抽象)工厂或工厂方法。