How to in-place construct an optional aggregate? It seems I can only construct an optional single thing, and not an optional aggregate of things.
#include <optional>
#include <iostream>
struct Unmovable
{
Unmovable(const Unmovable&) = delete;
Unmovable(Unmovable&&) = delete;
Unmovable& operator=(const Unmovable&) = delete;
Unmovable& operator=(Unmovable&&) = delete;
explicit Unmovable(const char* msg) {
std::cout << msg << '\n';
}
};
struct Things
{
Unmovable one;
Unmovable two;
};
int main(int argc, char* argv[]) {
const bool y = argc > 1 && argv[1][0] == 'y';
std::optional<Unmovable> optionalThing = y
? std::optional<Unmovable>{"works"}
: std::nullopt;
std::optional<Things> optionalThings = y
? std::optional<Things>{
#if ATTEMPT == 1
"jadda", "neida"
#elif ATTEMPT == 2
{"jadda", "neida"}
#elif ATTEMPT == 3
Things{"jadda", "neida"}
#elif ATTEMPT == 4
Unmovable{"jadda"}, Unmovable{"neida"}
#elif ATTEMPT == 5
{Unmovable{"jadda"}, Unmovable{"neida"}}
#elif ATTEMPT == 6
Things{Unmovable{"jadda"}, Unmovable{"neida"}}
#elif ATTEMPT == 7
std::in_place_t{}, "jadda", "neida"
#elif ATTEMPT == 8
std::in_place_t{}, {"jadda", "neida"}
#elif ATTEMPT == 9
std::in_place_t{}, Things{"jadda", "neida"}
#elif ATTEMPT == 10
std::in_place_t{}, Unmovable{"jadda"}, Unmovable{"neida"}
#elif ATTEMPT == 11
std::in_place_t{}, {Unmovable{"jadda"}, Unmovable{"neida"}}
#elif ATTEMPT == 12
std::in_place_t{}, Things{Unmovable{"jadda"}, Unmovable{"neida"}}
#endif
} : std::nullopt;
}
If you can use C++20, then what you want is
std::optional<Things>{std::in_place, "jadda", "neida"};
as seen in this live example. The reason you need C++20 is that the std::in_place_t
constructor uses the form of
T(std::forward<Args>(args)...)
to initialize the object, but ()
only works for classes that have a constructor, which Things
does not. C++ was updated to fix this, and that change made it into C++20.
In C++17 you can get this code to work by providing a constructor for Things
that will initialize the members. That would look like
struct Things
{
Things(const char* msg1, const char* msg2) : one(msg1), two(msg2) {}
Unmovable one;
Unmovable two;
};
int main()
{
std::optional<Things>{std::in_place, "jadda", "neida"};
}
and you can see that working in this live example
In case you were curious, the new language added to handle this in C++20 can be found in [dcl.init.general]/15.6.2.2