13

If the base class depends on the template parameter, its scope is not examined in the unqualified name lookup. I can use the using declaration to introduce names from the base class. Suppose now I have a type alias template in the base class. Can the using declaration be used to introduce it into the derived class?

template<class T>
struct Base
{
    using Type1 = int;

    template<typename S>
    using Type2 = S;
};

template<class T>
struct Derived : Base<T>
{
    using typename Base<T>::Type1;           // Fine
    //using Type1 = typename Base<T>::Type1; // Also fine

    template<typename S>
    using Type2 = typename Base<T>::template Type2<S>;
};

Can the line for Type2 be replaced with something similar to the (uncommented) line for Type1?

Evg
  • 25,259
  • 5
  • 41
  • 83
  • No, that syntax is not allowed. Sorry. – L. F. Oct 13 '19 at 04:54
  • Introducing a template name into the derived class is possible and works fine with `gcc-9.2.0`. – cartoonist Oct 30 '19 at 14:52
  • @cartoonist, is it a compiler extension or a new C++ standard feature? What is the syntax? – Evg Oct 30 '19 at 15:10
  • I know about optional `typename` in C++20, but I don't see how it can be used here to introduce `Type2` as a template name. – Evg Oct 30 '19 at 15:17
  • Oh, I think I understood your question wrong. The only way that I know (and meant in my comment) is what you have written in the sample code for `Type2` of `Derived` class. Sorry for the confusion. – cartoonist Oct 30 '19 at 16:32
  • Actually, the syntax somehow makes sense because it should be denoted that the `Type2` from `Base` class is a template name. It either can be introduced as a template name with template parameter `S` (as you've written) or can be specialised; e.g. `using Type2 = typename Base::template Type2;` – cartoonist Oct 30 '19 at 16:33
  • 1
    @cartoonist, what I meant is something simple like this: `using Base::Type2;`, possibly with `typename`s and `template`s. – Evg Oct 30 '19 at 16:35

1 Answers1

0
template<class T>
struct Derived : Base<T>
{
    using Base<T>::Type2;

    void foo() {
        // Using the Type2 alias template
        // inside our class to declare a local variable.
        typename Derived::template Type2<int> i;
    }
};

// Using the Type2 alias template
// outside the class to declare another type.
using X = Derived<int>::Type2<int>;

This is the correct syntax, and all compilers that support C++11 should allow this. See here for a live demo.

what I meant is something simple like this: using Base<T>::Type2;, possibly with typenames and templates.

We don't need these disambiguators in the using declaration, but when we want to use Type2 in Derived, we still need:

  • the template disambiguator because Type2 is a template and Derived is dependent on T
  • the typename disambiguator to specify that Type2<...> is a type

See also: cppreference article on dependent names

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
  • [It doesn't work](https://godbolt.org/z/G67595bnj) like `Type2` in my example. – Evg Jun 14 '23 at 02:28
  • @Evg you still need `typename` and `template` when using this alias in `Derived`. I've adjusted the answer to cover this. – Jan Schultke Jun 14 '23 at 08:07
  • That was the point of the question - avoid `typename` and `template`. But in this case you don't need `using Base::Type2;` at all because `Type2` will be inherited from `Base`. Also try adding `Derived d; d.foo();` to force a compiler to instantiate `foo()`. – Evg Jun 14 '23 at 21:27
  • @Evg you're asking the impossible then. There is no way to create a using-declaration that disambiguates whether the member we're introducing into our scope is a template or not. There is only the `using typename Base::Type1;` syntax to disambiguate for types. See https://eel.is/c++draft/namespace.udecl#nt:using-declarator – Jan Schultke Jun 14 '23 at 21:58