c++ : std::visit not compilable under gcc
Asked Answered
F

1

6

Here is my code which compiles fine for clang but failed with gcc

#include <iostream>
#include <string>
#include <regex>
#include <variant>

struct Id {
    void SetValue(const std::string& item)
    {
        value = item;
    }

    std::string value;
};

struct Number {
    void SetValue(const std::string& item)
    {
        value = std::stoi(item);
    }
    int value;
};


using TokenBase
    = std::variant<Number, Id>;

struct Token : TokenBase {
    using TokenBase::TokenBase;

    template <typename T>
    [[nodiscard]] bool Is() const {
        return std::holds_alternative<T>(*this);
    }

    template <typename T>
    [[nodiscard]] const T& As() const {
        return std::get<T>(*this);
    }

    template <typename T>
    [[nodiscard]] const T* TryAs() const {
        return std::get_if<T>(this);
    }
};

struct LexerTokenExtractor {
    const std::string& item_;

    void operator()(Number& item) const {
        item.SetValue(item_);
    }

    void operator()(Id& item) const {
        item.SetValue(item_);
    }
};


int main()
{
  const std::string string_token("x");
  Token id_token = Id();

  std::visit(LexerTokenExtractor{string_token}, id_token);

  std::cout << "ok" << std::endl;
}

Here is the log :

required from here
/usr/include/c++/7/variant:97:29: error: incomplete type ‘std::variant_size<Token>’ used in nested name specifier
     inline constexpr size_t variant_size_v = variant_size<_Variant>::value;

/usr/include/c++/7/variant: In instantiation of ‘constexpr const auto std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>::_S_vtable’:
/usr/include/c++/7/variant:711:29:   required from ‘struct std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>’
/usr/include/c++/7/variant:1255:23:   required from ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = LexerTokenExtractor; _Variants = {Token&}]’
1673947047/source.cpp:65:57:   required from here
/usr/include/c++/7/variant:711:49: error: ‘_S_apply’ was not declared in this scope
       static constexpr auto _S_vtable = _S_apply();

Please give me any ideas of what could be wrong here

Fluorosis answered 19/7, 2021 at 13:21 Comment(7)
Looks like gcc.gnu.org/bugzilla/show_bug.cgi?id=90943Corporeity
is there any workaround for this?Fluorosis
I'm not sure, but you might want to rethink your design anyway; inheriting from std types is typically not recommended.Corporeity
@Corporeity yet your own link has this: open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2162r2.htmlKinematics
@Kinematics Yeah, that's true :) There may well be a valid use case here (I haven't read that paper yet). But if the code doesn't compile, perhaps not inheriting for now (until the bug is fixed at least), is a reasonable approach.Corporeity
@Fluorosis not in GCC. Until it implements proposal linked above, you won't be able to use visit with your custom types, inherited from variant. If you have to do what you are trying to do, you'd have to use non-std implementation. Did you try boost.org/doc/libs/1_76_0/doc/html/variant.html ?Kinematics
@Kinematics I have not tried boost for this because it's not used inside the whole project. Originally I used this code with clang and was surprised when I faced with this compilation error. So I have to redesign my solution. Thanks for supportFluorosis
A
7

As mentioned in the comments, this is a known bug in the current versions of GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90943

A simple workaround would be to force std::visit() to operate directly on the variant instead of the subclass by using a static_cast.

std::visit(LexerTokenExtractor{string_token}, static_cast<TokenBase&>(id_token));

See on godbolt: https://gcc.godbolt.org/z/vMGfahq3z

Antipater answered 19/7, 2021 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.