Created a serializable object that can handle primitive types I don't need a lot and I don't need for my code to handle everything.  Even now, I'm just looking at handling serialization.  I'm pretty much building on it as needed.  I am trying to support vectors right now and am looking for an idea on how to extend what I have a little to support this.  Basically I've created a property class that has a callback function when the property changes (keeping it simple with equals operator for now).  This updates a dictionary object that can be serialized.  Below is my code.  It's my first time posting.  If I didn't follow some rules by accident, I'd love some guidance.  Working sample here: https://onlinegdb.com/H10iJVC3f

#include &lt;iostream&gt;
#include &lt;functional&gt;
#include &lt;sstream&gt;
#include &lt;map&gt;

using namespace std;

template &lt;class T&gt;
class Prop
{
public:
   Prop(const std::string &amp;key, const std::function&lt;void(std::string, std::string)&gt; &amp;changed);

private:
   std::string Key;
   T Value;
   std::function&lt;void(std::string, std::string)&gt; changed;

public:
   void operator=(const T &amp;value) {
      this-&gt;Value = value;
      this-&gt;changed(this-&gt;Key, static_cast&lt;ostringstream&amp;&gt;(ostringstream() &lt;&lt; value).str());
   }
};

template &lt;class T&gt;
Prop&lt;T&gt;::Prop(const std::string &amp;key, const std::function&lt;void(std::string, std::string)&gt; &amp;changed)
{
   this-&gt;Key = key;
   this-&gt;changed = changed;
}

class TheList
{
private:
   std::map&lt;std::string, std::string&gt; theList;

protected:
   void Update(const std::string &amp;key, const std::string &amp;value);

public:
   std::string ToJson();
};

void TheList::Update(const std::string &amp;key, const std::string &amp;value)
{
   theList[key] = value;
}

// TODO: body of this method will change and will use a processing library.
std::string TheList::ToJson()
{
   std::string json = "{\n";

   for (auto it : theList)
   {
      json += "\t\"" + it.first + "\": " + "\"" + it.second + "\",\n";
   }

   json.pop_back();
   json.pop_back();

   json += "\n}";

   return json;
}

// A Serializable object.
class User : public TheList
{
public:
   User();

public:
   Prop&lt;std::string&gt; Name;
   Prop&lt;short&gt; Age;
   Prop&lt;std::string&gt; Address;
};

User::User() : Name("Name", std::bind(&amp;User::Update, this, std::placeholders::_1, std::placeholders::_2)),
Age("Age", std::bind(&amp;User::Update, this, std::placeholders::_1, std::placeholders::_2)),
Address("Address", std::bind(&amp;User::Update, this, std::placeholders::_1, std::placeholders::_2))
{
}

int main()
{
    User user;

    user.Name = "Pamela";
    user.Age = 25;
    user.Address = "USA";

    std::string json = user.ToJson();

    cout &lt;&lt; json &lt;&lt; endl;

    return 0;
}
Don’t say using namespace std;.

And you were qualifying names in std anyway!  What gives?



std::function&lt;void(std::string, std::string)&gt; &amp;changed)


Why must you pass the strings by value to the callback?

You have this std::function signature spelled out twice — you might want to make an alias for that.

using cbfunc = std::function&lt;void(std::string, std::string)&gt; changed)
  ⋮
⋯Prop(const std::string&amp; key, const cbfunc&amp; changed)




In C++, the style is to put the &amp; modifier with the type, not the declared name.  This has been true since Bjarne’s original book, where it is pointed out explicitly.



this->Key = key;
   this->changed = changed;

No…
Write your constructor initializers, not assignment on top of default-initialized members.  Learn the difference between initialization and assignment.

: Key{key}, changed{changed}


and note that having the parameter with the same name as the data member is not a problem and is in fact idiomatic.  If you ever need to write this-&gt; a lot, you are doing something wrong.

In this particular case, take advantage of move semantics.  In full:

Prop&lt;T&gt;::Prop(std::string key, cbfunc changed)
: Key{std::move(key)}, changed{std::move(changed)}
{ }




static_cast&lt;ostringstream&amp;&gt;(ostringstream() &lt;&lt; value).str()


What’s with the static_cast?  Don’t do that.

Since you are modelling a value that does things behind the scenes when written to, using operator= for the name is probably OK in this case.  But it should not be void.  Either return *this or value.

Again, don’t use this-&gt; to access members.

Prop&amp; operator= (const T&amp; value)
    {
    set(value);
    return *this;
    }

void set (const T&amp; value)
    {
    Value= value;
    std::ostringstream&amp; fmt;
    fmt &lt;&lt; value;
    changed (Key, fmt.str());
    }


But, there is a handy package that already does the formatting exactly like this.  So just write

    Value= value;
    changed (Key, boost::lexical_cast&lt;std::string&gt;(value));


Note that I made a normal-named function set and then defined operator= to call it.  That will be much better for people who read your code later, since operator= carries certain expectations.



You did not provide the matching get function!  Your values are write-only!

In keeping the callbacks as invisible as possible, the design would be to have a function get and then an operator T that calls it.

 int x;
 Prop&lt;int&gt; px {"px", some_function};
 px = 5;  // invisible in
 x = px;  // and invisible out.




std::bind is deprecated since C++11.  Sometimes it is indeed the simplest way to write something.  But with placeholders, not so much.

Since all your props use the exact same function, you should just set it up once.

// member of class User
const auto binderCB = [this](std::string left, std::string right)
    { Update (left, right); }


Then the constructor※ is

User::User()
: Name{cb("Name")}, Age{cb("Age")}, ⋯


(just be sure cb is the first member so it is initialized first!)



(almost always) use auto.
You don’t have any uses at all, so I’ll point it out with an example in your main:

auto json = user.ToJson();




The main might be a throw-away example, but I’d rather initialize the user object in one go, not assign to each prop individually.

User user { "Pamela", 25, "USA" };


for a plain struct, this would just work as an aggregate initializer.  You need a constructor that takes three arguments (with defaults) to provide the same functionality.



Notes

※ I’d normally write all those as default initializers in-line and not give a constructor at all.  But for this specific example, I worry about referring to other members.  I’d need to look that up to see if it’s OK.

Rather than updating a map every time you change a value, you can use the same effort of setting up each member with an identifier and callback but provide a general way to explore the current values and types when you are ready to do something with them.  That is, pull rather than push.

There are libraries that do this, most notably Boost::Fusion.  But there are more modern ways — I think Boost::Hanna has that, but I don’t recall for sure.  An any case, the thing to do is to supply a non-member get template so the object can be used just like a tuple`.  This will let it interoperate with other code that follows this approach, including the built-in structured bindings. 

Since your callback turns everything into a string representation, your Json rendering will not know what things were originally strings and what are numbers.  Your code will output

"Age" : "25"


instead of

"Age" : 25


In your design (where everything is handed over as a string) you can include the quoting as part of the update callback.  Use one for strings that add quotes and also escapes out needed characters, and another for numbers that does not.  Then, don’t add the quotes in your outputing function.