MSVC bug in fold expression using variant?
Asked Answered
G

0

10

Consider following code:

#include <variant>

class A {};
class B {};

template<typename... Ts, typename Variant>
bool constexpr is_of(const Variant& variant)
{
  return std::visit(
      [](const auto& v) {
        using V = std::decay_t<decltype(v)>;
        return (std::is_same_v<V, Ts> || ...);
      },
      variant);
}


int main()
{
  using Variant = std::variant<A, B>;
  static_assert(is_of<A>(Variant{A{}}));
  static_assert(!is_of<B>(Variant{A{}}));

  static_assert(is_of<B>(Variant{B{}}));  // Fails
  static_assert(!is_of<A>(Variant{B{}}));  // Fails
  
  static_assert(!is_of<int>(Variant{A{}}));
  static_assert(!is_of<int>(Variant{B{}}));
  return 0;
}

is_of is a function which returns whether the value in a variant matches a range of types.

Why do the two static_asserts fail? GCC and clang behave as expected.

I was not able to reduce the example even more. The visit and the fold expression seem to be crucial, when I expand it using if constexpr, it works as expected.

https://godbolt.org/z/Wbd3GPzbc

Griner answered 23/8, 2024 at 15:23 Comment(4)
It's truly bizarre. typeid(V).name() produces "class B" when outside the fold expression, but "class A" when inside. Demo. Gotta be a bug.Rosabelle
looks like a bug, but workaround is simple std::disjunction_v<std::is_same<V, Ts> ...>Hershel
another workaround is taking the fold expression out of the lambda (that seems to be what triggers compiler to always select the first alternative). For example, template<class T, class...V> concept any_same = (std::same_as<T, V> || ...); and later in lambda use return any_same<V, Ts...>;Hershel
MSVC issue reported: developercommunity.visualstudio.com/t/…Taddeusz

© 2022 - 2025 — McMap. All rights reserved.