On 11/21/2014 09:29 PM, Andrzej Krzemienski wrote:
...
(1) In C++ we have the converting constructor. This appears close to what you call "bringing T into the optional<T> land", but I claim it is not the same.
They are obviously not the same -- "bringing" is an action, "converting constructor" is the tool to execute that action... when needed. If we have the tool (the constructor) it does not mean we swing it indiscriminately and apply it everywhere it fits. There has to be logical justification to apply that constructor... not just mechanical ability to do that. The converter is a powerful tool. However, with that "hammer" we should not fall into the trap of seeing everything like a nail.
And the consequences of these nuance differences result in the problem in question.
To me the difference's not that "nuanced". "Action" and "tool" are like "walking" and "shoes", "singing" and "microphone".
Perhaps the notion of "bringing T into the optional<T> land" would be better reflected by an explicit constructor, or function make_optional().
Mechanically, yes. Logically I am sure there are places where the action (of T to optional<T>) is unequivocal. If my API requests optional<T>, then I explicitly say -- I deal with optional<T> and apply optional<T> rules. I.e. my API is in the optional<T> land. So, when you provide T instead, it's propagated to optional<T> at the point of entering my API. The same as feed 'int' to func(double). It's not controversial, is it? How func(optional<T>) is different?
I am not saying that the converting constructor is wrong here. I am just saying that the motivation is *slightly* different than "bringing T into the optional<T> land", it is more for syntactic convenience, which is almost the same, but not same. (2) Your philosophy "when the direction of conversion is not as clear, we refuse applying it" -- there is no way to apply it within the definition of optional. We can apply it by poisoning every operation in the world that takes T or optional<T>. But that looks impractical. Back to Vicente's concern: User defining its own function
void f(optional<T>, optional<T>);
would need to add the following?
void f(T, optional<T>) { BOOST_STATIC_ASSERT(); } void f(optional<T>, T) { BOOST_STATIC_ASSERT(); }
What if there are 3 optional parameters? We can not say to the user that they need to program this way.
IMO no need complicating the matter with number of parameters. Just one will do. Are you implying that for every void f(optional<T>); we need to have poisoned void f(T) { BOOST_STATIC_ASSERT(); } As I tried to describe above, if I specify "void f(optional<T>, optional<T>);" as my API, then I explicitly say that it plays by optional<T> rules. It's no different from "void f(double, double);" called with "ints". If playing be optional<T> rules might be different for T rules or potentially confusing, I suggest we poison it. op<(T, optional<T>) is an excellent example because it implements interaction of its two arguments and that interaction s different if 1) both args are T; 2) both args are optional<T>; 3) args are of different types. As they are different, we should have 3 different implementations... #3 just happens to be no-implementation. I might well fail to understand your concern as those examples above seem far too hypothetical. If you can come up with a realistic example, that'd probably help me to see what you see.
I do not think it has been addressed.