0

The C++17 standard says that the std::in_place constructors of std::optional must be explicit (the same was with boost::optional). But why?? What is the reason behind this?

It forbids to have a nice code like this:

struct Value
{
    Value(int) { }
};

std::optional<Value> giveValueFive()
{
    return {std::in_place, 5}; 
}
Vahagn
  • 4,670
  • 9
  • 43
  • 72
  • 1
    `{inplace, 5}` is a "construction-description" of an optional, therefore it seems to make sense that it's `explicit`. Compared to `{none}` or `{5}` which expresses the absense or the value of an `optional`. – Johannes Schaub - litb Oct 28 '16 at 18:21
  • @JohannesSchaub-litb Didn't get the point. – Vahagn Oct 28 '16 at 18:48
  • 2
    The reason for `vector v(5, 0)` to be explicit is that it's a "construction description": "construct the vector by initializing with 5 zeros". Yours is sort-of "construct the optional by callings the embedded `Value` constructor with `5`.". You're not assigning a value as in `5`, `{5}` or in `{1, 2, 3, 4, 5}` (for the vector case). The "abstract value" of an `optional` does not comprise an "in_place" tag, that's just a helper to help you tell it how you want your `optional` to be constructed. Therefore, I find it intuitive that the constructor is `explicit`. – Johannes Schaub - litb Oct 28 '16 at 18:53
  • 1
    So it rather seems you want to ask about "why can't i use explicit constructors in `return {things}`. In fact, this was often desired even by C++ experts, but I suspect there was lack of consensus for a change. – Johannes Schaub - litb Oct 28 '16 at 18:57
  • 1
    Most `explicit` constructors in the standard library are likely there to avoid bog-standard implicit conversions: `void f(optional); f(std::in_place); ` shouldn't compile. It's not obvious to me whether the `{std::in_place, 5}` form was considered and found undesirable in particular, but since `{std::in_place}` cannot be allowed to compile symmetry would be a reasonable argument against it. – T.C. Oct 28 '16 at 19:04
  • @JohannesSchaub-litb: "*You're not assigning a value as in 5*" But he is constructing it by assigning it the value 5. `Value` is implicitly constructible from an `int`. Therefore, it can be assigned the value 5. The way to spell that with `optional` requires the use of an in-place constructor. Also, where is this "construction description" stuff coming from? – Nicol Bolas Oct 28 '16 at 20:56
  • @NicolBolas it's a free translation by myself of the phrase *constructing by calling a constructor (a "ctor-call")*, as opposed to the "assigning a value" which they call *constructing by transferring a value (a "conversion")* in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2640.pdf – Johannes Schaub - litb Oct 28 '16 at 21:01
  • @NicolBolas i disagree. He does not construct it by assigning the value 5. He constructs it by constructing the stored `Value` with `5` as constructor argument. As an example, `optional> o{std::in_place, new int}` is perfectly OK. But assigning `new int` to `shared_ptr` should/is not be OK, it should not be/is not an implicit conversion. So, perhaps make the relevant `optional` constructor conditionally-explicit? Then you can still not write `{std::in_place, new int}`, which would be an arbitrary difference IMO. – Johannes Schaub - litb Oct 28 '16 at 21:12
  • @JohannesSchaub-litb The reason why `std::vector v(5, 0)` (meaning "construct the vector by initializing with 5 zeros") is `explicit'` I guess is obvious: otherwise it would conflict (e.g. in the return statement) with `std::vector v{5, 0}` (meaning "construct the vector of size 2 and initialize the first element by 5 and the second element by 0"). There is no such conflict int the case of `std::optional`, so I don't think the analogy is appropriate. – Vahagn Oct 29 '16 at 07:50
  • @JohannesSchaub-litb I would not ask "why can't i use explicit constructors in `return {things}`" I would rather ask why can't I call `ff({std::in_place, 5})` for `void ff(std::optional<5>)` ։) – Vahagn Oct 29 '16 at 07:57
  • The point of this question is not only "coding with less wording" (though it is also a point). That `explicit` constructor forces me to have an extra move-constructor call like: `std::optional giveValueFive() { return std::optional{std::in_place, 5}; }` – Vahagn Oct 29 '16 at 08:05
  • @Vahagn If that's your only concern, then worry not. There won't be a move constructor invoked there. – Barry Nov 02 '16 at 17:47
  • @Barry But that's thanks to the optimization, right, not the standard? – Vahagn Nov 08 '16 at 14:55
  • @Vahagn C++17 has mandatory copy elision. – Barry Nov 08 '16 at 16:03

0 Answers0