【发布时间】:2018-12-04 17:08:37
【问题描述】:
考虑以下两个程序:
#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()>();
}
和
#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 编译这两者并输出预期的结果。在这两种情况下,Clang 都不会编译它们中的任何一个,并显示以下错误消息:
<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;
这两个程序的格式是否正确?如果不是,为什么?
此外,如果它们的格式不正确,Clang 给出的错误消息是否合适?根据[variant.assign],移动赋值运算符应该是constexpr。
此外,根据(7.4),第二个示例中的赋值应该表现得等同于emplace<int>(...),后者未声明constexpr ([variant.mod])。这是否意味着第二个示例格式错误,因为模板参数不能被评估为常量表达式,或者措辞是否允许/要求这种行为?
编辑:
根据 cmets,如果使用 libc++,Clang 似乎编译并输出正确的结果,并且错误仅发生在 libstdc++ 中。这是标准库和编译器不兼容吗?
在这两种情况下都有效:
- GCC 8.2.0 "-std=c++17"
- Clang 7.0.0 "-std=c++17 -stdlib=libc++"
在这两种情况下都不起作用:
- Clang 7.0.0 "-std=c++17"
【问题讨论】:
-
无法复制;您使用的是哪个版本的 g++ 和 clang++?
-
如果你使用
-stdlib=libc++会怎样 -
看起来你的库有一个错误,因为
variant& operator=(variant&&) = default;应该是constexpr variant& operator=(variant&&) = default; -
clang 通过 libc++ Demo 接受它。
-
不是答案,但类似clang bug report
标签: c++ c++17 constexpr variant