Minimal Property system in c++17
There are several ways to approach this.

The classic object oriented way is to make Payload be a simple interface class

class IPayload {
    virtual ~IPayload() = default;
    virtual std::string   toStr() = 0;
    virtual PropertyValue fromStr(const std::string &amp;) = 0;
    virtual PropertyValue get() = 0;
    virtual void          set(PropertyValue) = 0;
}; 


And just create for each property its own instance of an implementation of the interface - depending on what kind of property one uses. This can be helpful when you need variety updating mechanisms to work simultaneously. Say, one Payload that stores the field only in memory, one that stores into both in memory and in a file, and one that forwards it to GUI - or a combination of these. This can be also helpful when you require specialized treatment for some properties - like time input property - that upon receiving std::string input it processes it according to some time conversion, i.e., read double and then converts it to seconds depending on the time unit specification, e.g., "5min" converts to 300 (seconds). The only issue is that you ought to instantiate a treatment for each property - which can be a hassle and make the class unsuitable for some trivial basic usages.

I don't see any circumstances when the std::function approach would better - unless one has to runtime change setters or something - which is kinda odd honestly.

Also you can try going in the opposite direction and detach the storage class from the "customized actions". Say, make a simple multipurpose ini file parser wrapping std::unordered_map&lt;std::string,std::string&gt; - or use an existing one like boost::ptree that can read and write xml and json in addition. While in the GUI simply call the right functions when user sets the fields. Whether it is viable / not viable / preferred option depends a lot on your development platform for the GUI as well as other nuances.

You can in fact combine the two methods. Use the boost::ptree for storing / parsing and for internal usage whilst class PropertySet make responsible for the GUI handling and just instantiate one from each other upon loading / saving / updating.