[英]Why does std::visit in an unsatisfied concept cause a compile error in gcc
This code:这段代码:
#include <concepts>
#include <string>
#include <variant>
struct any_callable {
public:
template<typename T>
void operator()(T&&) {}
};
template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };
int main() {
constexpr bool wrapped = is_variant<std::string>;
}
does not compile under gcc 11. It gives a bunch of errors about valueless_by_exception
and such.不能在 gcc 11 下编译。它给出了一堆关于valueless_by_exception
等的错误。 It does, however, compile under msvc ( godbolt ).但是,它确实在 msvc ( Godbolt ) 下编译。 Now as I understand concepts, in this instance, if it would usually fail to compile it will decay to false, otherwise to true.现在,据我所知,在这种情况下,如果它通常无法编译,它将衰减为 false,否则为 true。 The behaviour of msvc would seem to support this. msvc 的行为似乎支持这一点。
So: Is this a bug in gcc, a non-standard feature of msvc, and/or is my code wrong?所以:这是 gcc 中的错误,msvc 的非标准功能,和/或我的代码有错吗?
That this:那个:
template<typename V>
concept is_variant = requires(V v) { std::visit(any_callable{}, v); };
works at all is a very recent change, a result of P2162 .完全有效是最近的变化,这是P2162的结果。 In order for this check to work, you need std::visit
to be what's usually referred to as "SFINAE-friendly".为了使此检查工作,您需要std::visit
成为通常所说的“SFINAE-friendly”。 That is: it must somehow be constrained on "variant-ness" such that if V
is a variant, it works, and if V
is not a variant, then visit
is removed from the overload set such that this call is an invalid expression (so that the concept
can be rejected).也就是说:它必须以某种方式被限制在“变体”上,这样如果V
是变体,它就可以工作,如果V
不是变体,那么visit
从重载集中删除,这样这个调用就是一个无效的表达式(以便可以拒绝该concept
)。
However, prior to P2162, there were no Constraints on std::visit
.但是,在 P2162 之前, std::visit
没有约束。 It was not SFINAE-friendly: the call would either work or be ill-formed.这不是 SFINAE 友好的:调用要么有效,要么格式错误。 It was this paper that added the constraint that the types that you're passing into it are variants (or inherit from one).正是这篇论文添加了一个约束,即您传递给它的类型是变体(或从一个变体)。 That's why you're seeing the error you're seeing: the call to visit
was failing, but not in a way that was friendly to the concept
check.这就是为什么您会看到您所看到的错误: visit
调用失败,但不是以对concept
检查友好的方式。
Post-P2162 (which, as the paper points out, MSVC already implemented, but libstdc++ did not), your check will be valid.在 P2162 之后(正如论文所指出的,MSVC 已经实现,但 libstdc++ 没有实现),您的支票将有效。
But we can do this easier in C++20 without having to go into the variant machinery - by checking the variant-ness directly in the same way that the paper does it:但是我们可以在 C++20 中更容易地做到这一点,而无需进入变体机制 - 通过以与论文相同的方式直接检查变体性:
template<typename V>
concept is_variant = requires(V v) {
[]<typename... Ts>(std::variant<Ts...> const&){}(v);
};
That lambda is invocable with v
if either v
is a variant
or it inherits from one.如果v
是一个variant
或者它继承自一个variant
,那么该 lambda 可以用v
调用。 Otherwise, it's ill-formed.否则,它是错误的。 This is more straight-forward than going through visit
.这比通过visit
更直接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.