AnswerBun.com

In C++, is it possible to make a variable simultaneously easy to access and easy to iterate over?

Stack Overflow Asked by nintendoeats on December 15, 2020

I am refactoring a "profiles" system with the goal of reducing the amount of repeated code required to save, load, and access settings. However, I am finding that I am just shuffling the repeated code around (decreasing it in one place increases it in another). I feel like I am missing something.

Note, in this scheme there is a concept of the "default" profile, which is selectively masked by the "loaded" profile. The user can configure all settings in the default profile, then just change specific settings for other profiles. For example, the user might want to use the same port number for all profiles (defined in the default profile), but specify a different IP address for connecting to different computers (defined in the loaded profile).
This functionality is not actually implemented yet, it is part of the reason I am refactoring.

Each setting has to be associated with the following information:

  1. A string used to identify it in XML.
  2. An int, bool, or string, which specifies the actual setting value.
  3. A boolean, which specifies whether to use the above value or the default.

Initially, I defined all of these as member variables of a struct. This is very easy to use for accessing settings. I can just pass the profile struct to any function that needs the settings, then access a particular setting using profile.thingy.

Unfortunately, saving and loading settings in this scheme requires adding separate save/load code for each setting. Similarly, to generate a "merged" settings profile that combines the default and current profiles will require manually coding merging for each setting. I also needed to add separate "useDefault" and "xmlName" variables for each setting. It was all a bit silly.

To start with, I implemented a class template SerfSetting which contains the 3 pieces of data mentioned earlier.

    template <class T>
class SerfSetting {
public: 
    T value;
    string xmlName;
    bool useDefault = false;

This is a little bit more annoying to access, since now I need to write profile.setting.value everywhere, but that’s not so bad. I also overloaded = and == to operate on value instead of the object itself, so sometimes this is transparent.

The real problem is when I try to turn this into something iterable, to save myself from having to repeat S/L/M (saving/loading/merging) code for every new setting.

What I’m looking at right now is using std::any, or a separate std::vector or std::map for each type of data. For S/L/M these would be perfect, very simple to iterate over. However, accessing a setting then becomes profile.listOfSettings[SETTING_INDEX_CONSTANT].value (or similar), which is pretty absurd for a common task and adds a potential for runtime bugs that might be difficult to catch (since I need to manually maintain the setting index constants, and manually ensure that the correct setting is being accessed).

Ideally I would be able to just iterate over the member variables of the profile struct, but the internet is quite clear that "C++ does not support reflection" and the alternatives I have seen are just as contrived and ugly as what I described above.

Is there a sensible solution to this problem, or am I resigned to having something ugly somewhere?

Thanks!

One Answer

I appreciate your comments, and am happy to now be aware of those tools (though I'm not sure std::optional applies in this case, since all values are expected to be non-null when they are accessed).

As often happens, taking the time to clearly state the problem in words helped me to solve it. I realized after posting, I was making the false assumption that I needed to access and iterate over the settings using the same object.

I believe that the simple solution is this:

struct SerfProfile {

    vector<SerfSetting<string>*> stringPtrList;

    SerfSetting<string> IPaddress = SerfSetting<string>();

    SerfProfile() {
        stringPtrList.push_back(&IPaddress);
    }
};

I can access the setting using IPaddress.value and iterate over the settings using stringPtrList . This also makes it easy to make profile settings that are not S/L/M, if I ever need to do that for some reason.

I appreciate you taking the time to look over this problem.

Answered by nintendoeats on December 15, 2020

Add your own answers!

Related Questions

SQL Query [Count the result of a query]

0  Asked on February 3, 2021 by abdelhalim

     

function stops when fetch() fails

2  Asked on February 2, 2021 by uncannyorange

 

merging lists of dataframes in R effectively

1  Asked on February 2, 2021 by user5813583

   

The Math behind a tesorflow.tensordot()

0  Asked on February 1, 2021 by harsh-dhamecha

     

How to check if a word contains one letter from another string

3  Asked on February 1, 2021 by umar-zahid

   

How to use citeproc-java on Android

1  Asked on February 1, 2021 by hector

     

Laravel whereHas Filter sub relation

1  Asked on February 1, 2021 by bryant-tang

 

How to check if list contains dict element with same key

1  Asked on February 1, 2021 by radosaw-hryniewicki

     

react-navigation nested drawer items

1  Asked on February 1, 2021 by caner-akmak

     

Add a header to an outgoing request by a filter in WebFlux

1  Asked on February 1, 2021 by jae-young-lee

     

Ask a Question

Get help from others!

© 2022 AnswerBun.com. All rights reserved. Sites we Love: PCI Database, MenuIva, UKBizDB, Menu Kuliner, Sharing RPP, SolveDir