C++ 模板可以帮助定义一行 'property' 成员吗?

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

背景:

我想在 C++ 中创建一个模仿 .NET 的 Properties.Settings.Default.

settings class

对于不知道它是什么的人来说,基本上它是一个单例 class,您可以在其中存储 application settings.

我的尝试:

单例 class: 到目前为止一切顺利,感谢 C++ Singleton design pattern

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

的地方

这是一个典型的 属性,带有 getter 和 setter:

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的QSettingsclass获取如:

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()
    {
        // 

        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 并且似乎没有必要为它们设置不同的类型。我也不知道 "good old macros",我只知道糟糕的旧宏 ;)。

你可以写一个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 =...
     }}}