
Robert Kawulak skrev:
Hi Thorsten,
2008/12/5 Thorsten Ottosen <thorsten.ottosen@dezide.com>:
It has been advocated in other context as well, e.g. by scott meyers. The author of the bimap library was, initially, against it, citing some of the same sources as you do. He ended up being very happy with the members IIRC.
The discussion in [*] and other places is not great IMO.
Apparently there are groups of people that prefer either of the approaches, but I wouldn't like the review to become an ideological discussion on general style guidelines like this one.
Well, sometimes that is needed too.
template <typename V, typename C, typename E, typename T> void change_constraint(constrained<V, C, E> & c, const T & new_constraint) { constrained<V, C, E> tmp(c.value(), new_constraint, c.error_handler()); c.swap(tmp); }
this seems *very inefficient* compared to only changing the constraint.
You can't simply change the constraint if the current value does not conform to it.You have to check that and eventually copy the value and the constraint, call the error policy for them and assign them back. In most common cases this seems not much more efficient than copying the whole object and swapping it (considering the typical case when one or both of the policies are empty or have trivial copy).
Having said that, I agree with you at this point -- implementing change_constraint as a member might allow for more efficient implementation for some cases. This is an argument that might convince me to make it a member and I will investigate this possibility.
It seems to me that it must be possible to check the new constraint without creating a new object. Often T is int or some other small build-in type, but I guess someone might use the library with a more heavy type.
But in general I still prefer writing non-members if there's no apparent reason why not to do so.
(b) The second claim is that free-standing functions break apart monolothic classes. That may be, but you don't have a monolothic class (you're not even close).
So how many functions that are unnecessarily members of a class must the class have to call it monolithic and to un-member those functions? :P
The classical example is std::string which is also what Sutter and Alexandrescu give as an example. But here the problem is that std::string are reimplementing generic algorithms. You don't have a monolithic class. Just like std::vector is not monolithic because erase is a member and not a free-standing function. This is another issue: functions that change the invariant-defining state of objects should be members.
And then finally my point, that the boost namespace is poluted with names that makes it near impossible to find the right function, and so, by making it a member that task is trivial.
Note that this function is in constrained_value namespace and does not pollute boost namespace.
Ok.
It is not that hard to find it, your editor may also help when you type '::' (although I agree that typing an object's name and '.' may be slightly more convenient).
In conclusion: making something a non-member is rarely a good idea.
In contrast: making everything a member is rarely a good idea. ;-)
Not when your modifying state, nor when you want to make the interface most easy to use. I'll give a good example of when a member should not have been added. Again, let's look at the (new) C++ standard library: they have added cbegin() and cend() members to all containers such that one can get a const_iterator from a mutable object. Instead, two generic function templates could have provided the same functionality with an O(1) coding effort vs. the chosen O(n) coding effort. -Thorsten