1

I'm trying to add a new constructor an existing class and wondering if I can somehow do an emplace initialization of an optional and then use that value in the initializer for another member value.

For example:

class sample {
    my_type sc;
    optional<opt_type> run;

    sample() :
        sc( gen_default() ) {
    }

    enum ctor_alt { ctor_alt };
    sample( ctor_alt ) :
        emplace( run, ctor_arg ), /* Possible somehow? */
        sc( run.field ) {
    }

My primary motivation is that I don't want to alter the type of my_type. There are many users of this variable and putting it in a wrapper would require changing a lot of code.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267

2 Answers2

5

emplace is a member function, and you cannot execute a member function until you've constructed the object (unless you're the object's constructor). But if you want to construct an engaged optional<T> in-place, you can simply use the std::in_place constructor:

run( std::in_place, ctor_arg )

However, member initializers are always executed in the order in which the members are declared, not the order in the member initializer list (your compiler ought to warn you if you initialize them out of order). So if you want to use an earlier initializer to initialize a later variable, you have to order them correctly in your declarations:

optional<opt_type> run;
my_type sc;
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
3

Sure thing, just call the constructor of std::optional with std::in_place_t:

run{std::in_place, ctor_arg}

std::in_place_t is a tag type to disambiguate when you want the type to construct the value in place instead of copying it.

If you want to use the value of the optional for another member variable, you need to make sure that that member variable comes after the optional, because member objects are initialized in the order that they appear.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162