Created attachment 44558 [details] preprocessed TU According to the standard, there is no assignment operator that should work in a constexpr context, however, I am able to successfully compile and use the following snippet: // gcc -lstdc++ -std=c++17 main.cpp @Linux laptop 4.17.11-arch1 x86_64 constexpr std::optional<int> foo() { std::optional<int> bar = 3; bar = 10; return bar; }
The code is valid. The optional<T>::operator=(U&&) assignment operator is not used when is_scalar<T> and is_same<T, decay_T<U>> (which is true here, where T=int and U=int). That means the assignment creates a temporary optional<int> using the constexpr constructor, i.e. bar = std::optional<int>(10); This is valid in a constexpr function.
Do I understand it correctly that this will get optimized into one statement saying bar = std::optional<int>(10); If so, is there something that could prevent such optimizations in order to check if the code is portable? Also, just to clarify, this has nothing to do with this proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r3.html to which someone has pointed me to?
(In reply to bobogu from comment #2) > Do I understand it correctly that this will get optimized into one statement > saying > > bar = std::optional<int>(10); No, it's not an optimization. When you assign an int to optional<int> it is equivalent to constructing a temporary optional<int> and then assigning that to the left-hand operand. > If so, is there something that could prevent such optimizations in order to > check if the code is portable? It's not an optimization, it's the required behaviour according the the specification of std::optional in the standard. > Also, just to clarify, this has nothing to do with this proposal > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r3.html to > which someone has pointed me to? It's nothing to do with that.
(In reply to Jonathan Wakely from comment #3) > (In reply to bobogu from comment #2) > When you assign an int to optional<int> it is equivalent to constructing a > temporary optional<int> and then assigning that to the left-hand operand. I feel stupid, but I still don't understand how that can work in a constexpr context when the current c++17 standard doesn't specify any constexpr assignment operator. The second line of this snippet std::optional<int> bar = 3; bar = std::optional<int>(10); would call the 3rd assignment operator (https://en.cppreference.com/w/cpp/utility/optional/operator%3D), right? And the operator isn't constexpr, but works in a constexpr function.
(In reply to bobogu from comment #4) > I feel stupid, but I still don't understand how that can work in a constexpr > context when the current c++17 standard doesn't specify any constexpr > assignment operator. That's true, but the standard is broken. All implementations define the assignment operator as defaulted, and so the compiler makes it constexpr. In fact the p0602R3 proposal you linked to is relevant, because it would *require* implementations to define the operator as defaulted (in order to be trivial) and so the compiler is always going to make it constexpr for std::optional<int>. Anyway, I don't consider "I can use more things in constant expressions than the standard says" to be a bug.
(In reply to Jonathan Wakely from comment #5) > In fact the p0602R3 proposal you linked to is relevant, because it would > *require* implementations to define the operator as defaulted (in order to > be trivial) and so the compiler is always going to make it constexpr for > std::optional<int>. I've raised this with the standards committee.
(In reply to Jonathan Wakely from comment #5) > (In reply to bobogu from comment #4) > All implementations define the assignment operator as defaulted, and so the > compiler makes it constexpr. > > In fact the p0602R3 proposal you linked to is relevant, because it would > *require* implementations to define the operator as defaulted (in order to > be trivial) and so the compiler is always going to make it constexpr for > std::optional<int>. Ah, finally it makes sense to me! > Anyway, I don't consider "I can use more things in constant expressions than > the standard says" to be a bug. All right, I'm sorry then... I just thought that as this is undocumented, it could lead to producing an unportable code. Anyway, thank you for clearing it out. > I've raised this with the standards committee. Thanks!
(In reply to bobogu from comment #7) > All right, I'm sorry then... I just thought that as this is undocumented, it > could lead to producing an unportable code. It could, except that you should get the same behaviour for every correct implementation. Your example doesn't compile with libc++, but that's a bug: https://bugs.llvm.org/show_bug.cgi?id=38638
(In reply to Jonathan Wakely from comment #8) > (In reply to bobogu from comment #7) > > All right, I'm sorry then... I just thought that as this is undocumented, it > > could lead to producing an unportable code. > > It could, except that you should get the same behaviour for every correct > implementation. Your example doesn't compile with libc++, but that's a bug: > https://bugs.llvm.org/show_bug.cgi?id=38638 Yes, that was just my misconception before you got me on the right track - I thought clang's behaviour was correct because of what I saw in the standard :-)