C++模板是否有助于定义单行'property'成员?

Can C++ templates help in defining one-liner 'property' members?

本文关键字:成员 property 单行 是否 有助于 定义 C++      更新时间:2023-10-16

>Background:

我想在C++中创建一个模仿.NET 的属性.设置.默认。

对于不知道它是什么的人,基本上它是一个单例类,您可以在其中存储应用程序设置。

我的尝试:

单例类:到目前为止一切顺利,这要归功于C++单例设计模式

属性:这是我想获得一些基础设施帮助的地方

下面是一个典型的属性,带有一个吸气剂和一个二传手:

QString GetTheme()
{
return GetValue(ThemeKey, "Material").toString();
}
void SetTheme(const QString &value)
{
SetValue(ThemeKey, value);
}

这有效,但您可能已经猜到了我的问题:如何避免所有这些样板代码?

基本上,我想要实现的是某种单行来定义属性,例如:

// pseudo code ahead
// this property is of type QString and whose default value is "Material"
property<QString, "Material"> Theme;
// ideally it should be usable like that:
auto theme = Settings::Current.Theme(); // getter
Settings::Current.Theme("..."); // setter

会有不同类型的属性,如intboolQString等。

问题:

C++模板可以以某种方式帮助解决此问题,还是应该编写一个好的旧宏?

我也准备接受这种方法的任何体面的替代办法。

编辑:

我只是意识到我没有完全解释自己,对此感到抱歉。

这些属性的值将由Qt的QSettings类获取,例如:

QSettings settings;
settings.setValue("editor/wrapMargin", 68);

下面我粘贴了我当前的实现,以便您更好地了解如何获取属性的值:

#ifndef SETTINGS_H
#define SETTINGS_H
#include <QSettings>
#include <QString>
class Settings
{
private:
Settings()
{
}
QSettings Store;
QVariant GetValue(const QString &key, const QVariant &defaultValue = QVariant())
{
return Store.value(key, defaultValue);
}
void SetValue(const QString &key, const QVariant &value)
{
Store.setValue(key, value);
}
static const QString ThemeKey;
public:
Settings(Settings const&) = delete;
void operator=(Settings const&) = delete;
static Settings& Current()
{
// https://stackoverflow.com/a/1008289/361899
static Settings instance;
return instance;
}

QString GetTheme()
{
return GetValue(ThemeKey, "Material").toString();
}
void SetTheme(const QString &value)
{
SetValue(ThemeKey, value);
}
};
const QString Settings::ThemeKey = "ThemeKey";
#endif // SETTINGS_H

我不会将"Material"和其他参数用作模板参数,我的意思是它们只是string,似乎没有必要为它们设置不同的类型。我也不知道"好的旧宏",我只知道坏的旧宏;)。

你可以写一个Property

template <typename T> 
struct Property {
std::string category;
T value;
Property(const std::string& category) : category(category) {}
T operator()() { 
return value;
}
Property& operator()(const T& v) { 
value = v; 
return *this;
}
};

然后在单例中拥有该成员:

struct Settings {
Property<int> Theme{"Material"};
};

并像这样使用它:

int main(){
Settings s;
s.Theme(42);
std::cout << s.Theme();
}

在您的情况下,namespace就足够了吗?命名空间是一种单例实例化,由链接器和程序启动时的动态初始化一劳永逸地实例化。此外,命名空间可以在不同的翻译单元中扩展。

namespace Properties{
namespace Settings {
namespace Default {
inline constexpr auto myColor =...
}}}