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

phuclv
  • 37,963
  • 15
  • 156
  • 475
Dmitry
  • 1,912
  • 2
  • 18
  • 29
  • 1
    Looks like https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90943 – cigien Jul 19 '21 at 13:25
  • is there any workaround for this? – Dmitry Jul 19 '21 at 13:27
  • I'm not sure, but you might want to rethink your design anyway; inheriting from std types is typically not recommended. – cigien Jul 19 '21 at 13:28
  • @cigien yet your own link has this: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2162r2.html – SergeyA Jul 19 '21 at 13:29
  • @SergeyA 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. – cigien Jul 19 '21 at 13:31
  • @Dmitry 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 https://www.boost.org/doc/libs/1_76_0/doc/html/variant.html ? – SergeyA Jul 19 '21 at 13:33
  • @SergeyA 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 support – Dmitry Jul 19 '21 at 13:37

1 Answers1

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