Consider the following two programs:
#include<variant>
#include<iostream>
constexpr auto f() {
using T = std::variant<bool, int>;
T t(false);
t = T(true);
return std::get<bool>(t);
}
template<auto V>
void print() { std::cout << V << "\n"; }
int main() {
print<f()>();
}
and
#include<variant>
#include<iostream>
constexpr auto f() {
using T = std::variant<bool, int>;
T t(false);
t = T(42);
return std::get<int>(t);
}
template<auto V>
void print() { std::cout << V << "\n"; }
int main() {
print<f()>();
}
GCC compiles both of these and outputs the expected results. Clang does not compile any of them with the following error message in both cases:
<source>:4:16: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
constexpr auto f() {
^
<source>:7:7: note: non-constexpr function 'operator=' cannot be used in a constant expression
t = T(42);
^
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/variant:1095:16: note: declared here
variant& operator=(variant&&) = default;
Are the two programs well-formed? If not, why?
Also if they are not well-formed, is the error message Clang gives appropriate? According to [variant.assign] the move assignment operator should be constexpr
.
Furthermore according to (7.4) the assignment in the second example should behave equivalent to emplace<int>(...)
which is not declared constexpr
([variant.mod]). Does this imply the second example is ill-formed because the template argument cannot be evaluated as constant expression or does the wording allow/require this behavior?
EDIT:
Based on the comments it seems that Clang compiles and ouputs the correct results if libc++ is used and the error occurs only with libstdc++. Is this an incompatibility between the standard library and compiler?
Works in both cases:
- GCC 8.2.0 "-std=c++17"
- Clang 7.0.0 "-std=c++17 -stdlib=libc++"
Does not work in either case:
- Clang 7.0.0 "-std=c++17"
-stdlib=libc++
– Shafik Yaghmourvariant& operator=(variant&&) = default;
should beconstexpr variant& operator=(variant&&) = default;
– NathanOliver