Using `std::visit` on class inheriting from `std::variant` – `libstdc++` vs `libc++`

  • A+

Consider the following code snippet:

struct v : std::variant<int, std::vector<v>> { };  int main() {     std::visit([](auto){ }, v{0}); } 
  • clang++ 7 with -stdlib=libc++ -std=c++2a compiles the code;

  • g++ 9 with -std=c++2a fails to compile the code, with the following error:

    /opt/compiler-explorer/gcc-trunk-20180711/include/c++/9.0.0/variant:94:29: error: incomplete type 'std::variant_size' used in nested name specifier

     inline constexpr size_t variant_size_v = variant_size<_Variant>::value;                           ^~~~~~~~~~~~~~ 

live example on

  • Are both implementations conforming to the Standard?

  • If not, what implementation is correct here, and why?


Looks like it is a bug in gcc implementation. According to cppreference, it is called as if calling invoke on a std::get. std::get<> is defined for anything which is convertible to std::variant (since it accepts a std::variant argument by forwarding reference). Your structure is convertible to std::variant, and so std::get itself works on your structure in gcc.

The fact that the gcc implementation chose to use a std::variant_size as part of its implementation of visit is their implementation detail, and the fact that it doesn't (and shouldn't) work for your struct is irrelevant.

Conclusion: It is a bug in gcc due to an oversight in implementation.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: