2

I have a construct similar to the following in my code.

#include <optional>

struct C {
    struct C2 {
        bool b { false };
    };

    std::optional<C2> oc2;
};

int main(int argc, char** argv) {
    C c;
    c.oc2.emplace();    // clang error!
}

It's an std::optional object inside of a class that I want to initialize via its default constructor. The above code compiles fine in GCC 9. But Clang 9 fails with the following error:

% clang++-9 -std=c++17 -o main main.cpp                                                                                                                                                                            
main.cpp:13:11: error: no matching member function for call to 'emplace'
    c.oc2.emplace();
    ~~~~~~^~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/optional:845:2: note: candidate template ignored: requirement 'is_constructible_v<C::C2>' was not satisfied [with _Args = <>]
        emplace(_Args&&... __args)
        ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/optional:855:2: note: candidate function template not viable: requires at least argument '__il', but no arguments were provided
        emplace(initializer_list<_Up> __il, _Args&&... __args)
        ^
1 error generated.

Is this a Clang bug or is there a better way to initialize an optional value in that case?

fschoenm
  • 1,391
  • 13
  • 32
  • 1
    Works just fine [here](https://wandbox.org/permlink/aYzZ8xpNjzkXJ95z) – NathanOliver Dec 17 '19 at 15:34
  • 3
    I believe the problem is that `C::C2` is not properly defined when you declare the template `std::optional` because `C` is incomplete type. This is kinda nonsense but that's what it is. – ALX23z Dec 17 '19 at 15:36
  • Works for me with either `-stdlib=libc++` or `-stdlib=libstdc++` – Marshall Clow Dec 17 '19 at 15:38
  • 4
    Probably, related question: https://stackoverflow.com/questions/59252363/why-is-my-class-non-default-constructible – Evg Dec 17 '19 at 15:39
  • @Evg looks like we need to make that more generic so we can use it as a dupe target. – NathanOliver Dec 17 '19 at 15:43
  • 1
    This is very similar to https://stackoverflow.com/questions/47974898/clang-5-stdoptional-instantiation-screws-stdis-constructible-trait-of-the-parameter-type , but I'm not sure if the cause is the same. – cpplearner Dec 17 '19 at 15:49
  • @NathanOliver-ReinstateMonica very interesting, it works in g++ and not in clang when I try it out in godbolt: https://godbolt.org/z/fW3Dgd . If I take out that weird bool initialization in C2 (I didn't think that was legal for a non-const member?), it works fine. – parktomatomi Dec 17 '19 at 16:15
  • @parktomatomi I'm pretty sure the code has UB so it is not too surprising. – NathanOliver Dec 17 '19 at 16:18
  • Works in clang with `boost::optional<>` so it looks more like a library bug than a compiler bug to me. – Richard Hodges Dec 17 '19 at 16:59
  • @NathanOliver-ReinstateMonica Which part of the code do you think has undefined behavior? – fschoenm Dec 19 '19 at 12:57
  • @fschoenm See [this](https://stackoverflow.com/questions/59252363/why-is-my-class-non-default-constructible). `std::optional oc2;` gets instantiated immediately before the declaration of `C` and because of that `C2` is not a complete type in that instantiation and `std::optional` does not allow for an incomplete type so you have undefined behavior. – NathanOliver Dec 19 '19 at 13:23

0 Answers0