2

I'm trying to implement a variadic visitor class.

template<typename T>
class VisitorBaseFor {
protected:
   virtual ~VisitorBaseFor() = default;

public:
   virtual void visit(T &t) = 0;
};

template<typename... Ts>
class VisitorBase : public VisitorBaseFor<Ts>... {
public:
    using VisitorBaseFor<Ts>::visit...;
};

I know from that overload trick that variadic using declarations should be possible, but MSVC does not compile my code saying I need to expand Ts while both GCC and Clang compile my code without errors, see here.

What am I missing? Is this a MSVC bug or just not (yet) supported? If it is, is there a way to work around this?

Apart from that I have tried to remove the using declaration but then the calls to visit become ambiguous for some reason, even though all classes in Ts are not convertible to each other. This is being diagnosed correctly by MSVC, but why are they even used in overload resolution then?

Update: This is a known bug since at least Sep 03, 2018. See here and here.

Community
  • 1
  • 1
  • 1
    Re the “apart from” question: functions in different scopes don’t overload with each other, so you have to use the using. – L. F. Aug 19 '19 at 09:59
  • What do you think is the difference between a "bug" and "not supported"? – Sam Varshavchik Aug 19 '19 at 10:41
  • @SamVarshavchik [This](https://en.cppreference.com/w/cpp/compiler_support) is the list of currently supported features, a bug would be a incorrectly implemented feature. – Julian Wiesler Aug 19 '19 at 10:45

1 Answers1

3

Code is indeed correct and so bug of msvc.

Workaround is to manually do the recursion:

template<typename T>
class VisitorBaseImpl {
protected:
    virtual ~VisitorBaseImpl() = default;

public:
    virtual void visit(T &t) = 0;
};

template<typename... Ts> class VisitorBase;

template<typename T>
class VisitorBase<T> : public VisitorBaseImpl<T>
{
};

template<typename T, typename... Ts>
class VisitorBase<T, Ts...> : public VisitorBase<T>, public VisitorBase<Ts...>
{
public:
    using VisitorBase<T>::visit;
    using VisitorBase<Ts...>::visit;
};

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Yes I know of this workaround but this is what i was trying to evade... anyways thank you. – Julian Wiesler Aug 19 '19 at 10:43
  • 1
    Other workaround is possible [Demo](https://godbolt.org/z/JsUvD_), but is it more fragile, and doesn't support implicit conversion. – Jarod42 Aug 19 '19 at 10:49