不同类型C++的句柄设置

bz4sfanl  于 2023-05-08  发布在  其他
关注(0)|答案(1)|浏览(144)

我真的不知道如何解释我所面临的问题。这也让我很难在网上搜索答案。但我希望通过下面的代码示例可以澄清这个问题。

struct ISetting
{
    virtual void* GetValue() = 0;
};

template<typename T>
struct Setting : public ISetting
{
    T value;
    
    void* GetValue() 
    {
        return &value;
    }
};

struct Settings
{
    Setting<int> setting1;
    Setting<std::string> setting2;
    std::vector<ISetting*> allSettings;
    
    Settings()
    {
        allSettings.push_back(&setting1);
        allSettings.push_back(&setting2);
    }
    
};

int main()
{
    Settings settings;
    settings.setting1.value = 5;
    settings.setting2.value = "testing";
    
    for(int i=0; i<settings.allSettings.size(); i++)
    {
        void* value = settings.allSettings[i]->GetValue();
        
        printf("value = ...\n");
        
        
    }        
    return 0;
}

Try this code
如您所见,我有一个包含设置的结构。这些设置可以是不同的类型。现在我想把这些设置保存到flash中(这在微控制器上运行),所以我想循环所有的设置并相应地写下来。问题是,我不知道设置的类型,因为该类型由于接口而丢失。为了简化问题,我想将每个设置的值打印到输出。而不是写到flash。
我确实想出了一个解决办法,但我不确定这是正确的方法。一般的想法是设置通过其界面接受访问者。然后,实现的设置调用访问者中的适当函数,并将其本身作为变量。然后,该访问者知道如何处理此设置。

template<typename T>
struct Setting;

struct ISettingVisitor
{
    virtual void Visit(Setting<int>* setting) = 0;
    virtual void Visit(Setting<std::string>* setting) = 0;
};

struct ISetting
{
    virtual void Accept(ISettingVisitor* handler) = 0;
};

template<typename T>
struct Setting : public ISetting
{
    T value;
    
    void Accept(ISettingVisitor* handler)
    {
        handler->Visit(this);
    }
};

struct Settings
{
    Setting<int> setting1;
    Setting<std::string> setting2;
    std::vector<ISetting*> allSettings;
    
    Settings()
    {
        allSettings.push_back(&setting1);
        allSettings.push_back(&setting2);
    }
    
};

struct SettingsPrinter : public ISettingVisitor
{
    void Visit(Setting<int>* setting)           { printf("value = %d\n", setting->value); }
    void Visit(Setting<std::string>* setting)   { printf("value = %s\n", setting->value.c_str()); }
};

int main()
{
    Settings settings;
    settings.setting1.value = 5;
    settings.setting2.value = "testing";
    
    SettingsPrinter settingsPrinter;
    
    for(int i=0; i<settings.allSettings.size(); i++)
    {
        settings.allSettings[i]->Accept(&settingsPrinter);        
    }
    
    return 0;
}

Try this code
假设我想将设置导出为JSON格式。这将是沿着如下:

struct JSONExporter : public ISettingVisitor
{
    JSON* json = NULL;
    
    void Visit(Setting<int>* setting)           { json->AddInt(setting->name, setting->value); }
    void Visit(Setting<std::string>* setting)   { json->AddString(setting->name, setting->value); }

    std::string Export(Settings* settings)
    {
        json = new JSON();
        
        for(int i=0; i<settings.allSettings.size(); i++)
        {
            settings.allSettings[i]->Accept(this);        
        }
        
        
        std::string result = json->ToString();
        delete json;
        return result;
    }    
};

我想这可以工作,但我不确定是否存在更精简的解决方案。
也许还有一个附带的问题
是否可以定义设置对象,使您不会忘记将设置添加到列表中。大概是这样的

struct Settings
{
    MyIterableThing allSettings
    {
        Setting<int> setting1;
        Setting<std::string> setting2;
    };

    Settings()
    {

    }
    
};

void main()
{
    Settings settings;
    settings.setting1.value = 5;

    for (auto& it : settings.allSettings) 
    {
        //Do something
    }
}
ccrfmcuu

ccrfmcuu1#

你可以使用一个元组来代替基本的空指针向量:

template<typename T>
struct Setting {
    T value;
    
    Setting(T const& val) : value{val} {}
    
    // More setting related things...
};

struct Settings {
    Setting<int> setting1;
    Setting<std::string> setting2;
    // Assuming we absolutely need raw pointers outside this example.
    //  Otherwise I'd use smart pointers.
    std::tuple<Setting<int>*, Setting<std::string>*> allSettings;
    
    // By supplying our own constructor we've implicitly deleted the
    //  default constructor. Creating a Settings now requires specifying
    //  initial values through this constructor.
    Settings(int s1, std::string s2)
        : setting1{s1}, setting2{s2}, allSettings{&s1, &s2} {}
    
    // More allSettings related things...
};

int main() {
    auto settings = Settings{5, "testing"};
    
    // You can iterate though a std::tuple without C++17's std::for_each,
    //  but it requires some ugly design pattern.
    std::for_each(
        settings.allSettings, 
        // Instead of a templated lambda we could use a named
        //  function, as long as it's templated/has overloads for
        //  int and std::string.
        [](auto const& setting) {
            std::cout << setting->value << "\n";
        }
    );
       
    // In C++ and C99, main will return 0 if you don't specify anything.
}

相关问题