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. It does, however, compile under 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. The behaviour of msvc would seem to support this.
So: Is this a bug in gcc, a non-standard feature of msvc, and/or is my code wrong?
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. In order for this check to work, you need std::visit
to be what's usually referred to as "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).
However, prior to P2162, there were no Constraints on std::visit
. It was not SFINAE-friendly: the call would either work or be ill-formed. 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.
Post-P2162 (which, as the paper points out, MSVC already implemented, but libstdc++ did not), your check will be valid.
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:
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. Otherwise, it's ill-formed. This is more straight-forward than going through visit
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With