Re: Template setters
On Sunday, September 8, 2013 1:50:03 AM UTC+2, ?? Tiib wrote:
Have you considered avoiding those "setters"? Setters only make it
difficult for human brain that expects a "person" to "marry" or to
"divorce" and does not expect some random spaghetti function
somewhere to "set marital status", "set spouse", "set family name"
etc. instead.
Setters themselves have pros and cons and it's a long and still
ongoing debate whether to use them or not. I would like to avoid that
discussion here since I've seen it can turn into "religious" wars,
rather than exchange of arguments. Let's just assume they are being
used for some reasons.
You seriously oversimplify that pre-C++11 life. Move was also
traditionally there with pointer to non-const, with the sole
pre-C++11 smart pointer and with various things made by
developers. It was already used so it was made better supported by
language. Now there are additionally rvalue references and two new
smart pointers.
From one point of view, move was there, but it had to be done manually
every time, often leading to bizarre constructs like non-const
auto_ptr copy (pseudo-move) constructor. That approach was both
unintuitive and lead to code repetition, if someone wanted to go that
path (const + non-const versions of everything, which wanted to
support move). Now, we have the means to do it the right way and I
think we should try to take the opportunity (when appropriate), thus
my original idea.
Do you presume that "set spouse" (that sets relation with other
"person" object) and "set marital status" (that only sets some enum
attribute to /married/ or /single/) can somehow be handled
uniformly?
I feel that the suggested idiom can make parameter passing even more
complicated than it already is.
The use case for the setters, you give as an example, would stay the
same. This new approach would only allow the use of new language
features with the possibility of perfect forwarding the setter
argument to any operator = overload. Let's take for example:
class Gadget
{
public:
void setWidget(const Widget &w) { mWidget = w; }
private:
Widget mWidget;
};
Gadget object;
Widget w;
object.setWidget(w); // #1
object.setWidget(Widget()); // #2
With this old-style code, both versions pass the Widget object as
const &, which in turn causes copy-assignment to mWidget every
time. But, we don't need to make a copy in case #2, so why should we?
What if we want to move that #1 lvalue also? That necessitates the
creation of a new setter taking Widget &&, therefore leading to code
repetition. And don't get me started on const xvalues... I think my
templated approach with universal references provides a nice solution
to all that problems.
But you do have a point with making things complicated - it certainly
would. I don't think making a template would be the complication -
templates are all around. The real complication could come from
something like this:
class Widget
{
public:
...
Widget &operator =(int i) { ... }
};
class Gadget
{
public:
template<class T>
void setWidget(T &&w) { mWidget = std::forward<T>(w); }
private:
Widget mWidget;
};
Gadget object;
object.setWidget(1);
That is confusing. But he question here is - is it more confusing that
the operator = in Widget itself? Is the confusion the fault of the
setter or Widget? Or maybe, the setter uncovered some design flaw?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]