Why does public overload conflict with private using directive on some compilers?

I believe what applies here is [namespace.udecl]/17:

In a using-declarator that does not name a constructor, all members of the set of introduced declarations shall be accessible. In a using-declarator that names a constructor, no access check is performed. In particular, if a derived class uses a using-declarator to access a member of a base class, the member name shall be accessible. If the name is that of an overloaded member function, then all functions named shall be accessible. […]

(emphasis mine) in combination with [namespace.udecl]/19:

A synonym created by a using-declaration has the usual accessibility for a member-declaration. […]

The using declaration in MoreDerived creates a synonym for Derived::get which itself is a synonym for the overload set consisting of the member function Derived::get and the member function template Base::get. The latter is not accessible at the point of the using declaration in MoreDerived (because it is private in Derived). Thus, GCC and Clang are correct, this code should not compile. Moving the using declaration in Derived from the private to the public part, for example

template<typename T> class Derived : public Base
{
public:
  using Base::get;
  const T& get() const;
};

resolves the issue…


Michael Kenzel already explained nicely why your code did fail.

[...] but making get fail to compile for Derived is actually a feature of the original code

Although I cannot encourage such a pattern, as you are violating the "is a" relationship, the following might do the trick for you:

class Base
{
public:
  template<typename T>
  const T& get() const;
};

template<typename T> class Derived : public Base
{
public:
    template<typename U>
    U const& get() const = delete;
    T const& get() const { return Base::get<T>(); }
};

Probably a better option is to simply make the template getter protected instead.

Private inheritance of Base should solve the issue as well, if that's feasible for you; if not, another option might be moving the template getter to a new, separate base class which then will be inherited privately.

Both variants would prevent

Derived<int> d;
static_cast<Base>(d).get<double>();

as well, if this is meaningless anyway.