1

My understanding is that in C++ user defined types are inherited and indeed this seems to be the case up to a point.

Here is what I'm trying to do but this doesn't compile:

template <typename T>
struct A{
    using type = T;
};

template <typename T>
struct B: A<T>{
    using type2 = type;
};

However, if I have B extend A of a non template parameter it works:

template <typename T>
struct A{
    using type = T;
};

template <typename T>
struct B: A<int>{
    using type2 = type;
};

Indeed, one work around I found (but which doesn't really help me for what I'm trying to do is to scope type but this defeats the point of inheritance:

template <typename T>
struct A{
    using type = T;
};

template <typename T>
struct B{
    using type2 = A<T>::type;
};

Is there a proper way to achieve the behavior I want (in a more general case, this is obviously a toy example) and what are the semantics of this?

Edit: this is what I wish the code would look like, the lack of inheritance can be worked around but I wanted to understand what the limitations are

template <typename t>
struct instruction{
    public:
    using input = t::first;
    using mem = t::second;

    using newmem = mem;
    using newinput = input;

    using result = pair<newinput, newmem>;
};



template <typename t>
struct right_code: public instruction<t>{
    using newmem = buffer<cons<mem::list2::head, mem::list1>, (std::is_same<mem::list2::tail , nil> ? cons<zero, nil>
                                                                                                    : mem::list2::tail)>;
};

template <typename t>
using right = right_code<t>::result;



template <typename t>
struct left_code:instruction<t>{
    using newmem = (std::is_same<mem::list1::tail, nil ? mem
                                                       : buffer<mem::list1::tail, cons<mem::list1::head, mem::list2>);
};

template <typename t>
using left = left_code<t>::result;
Berindei
  • 11
  • 2
  • Can you show an example that demonstrates why `using type2 = A::type;` doesn't work for you? Some sort of explicit qualification is needed in this kind of situation involving a base class that depends on a template parameter; the question is what kind of construct you can live with. – Brian Bi Nov 24 '21 at 21:51
  • See [this](https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) for a possible duplicate. – 1201ProgramAlarm Nov 24 '21 at 22:28
  • I think the question is why, if `B` is an `A`, doesn’t `B::type` just exist, much as if `A` had `int foo() const;`, `B` would have it too. – Ben Nov 25 '21 at 02:38

1 Answers1

0

Use typename A<T>::type.

template <typename T>
struct A {
    using type = T;
};

template <typename T>
struct B : A<T> {
    using type2 = typename A<T>::type;
};

using type2 = type would not work for struct B : A<T> because type is a non-dependent name thus name lookup would not be affected by declarations visible on instantiation, see https://en.cppreference.com/w/cpp/language/unqualified_lookup

For example,

template <typename T>
struct A {
    using type = T;
};

template <>
struct A<int> : public C<int> {
    // it doesn't need to have `type`
};

A<T> doesn't even need to have type for some specialization. We see that declarations from A<T> are unsure until we instantiate it.

By using typename A<T>::type, we make a dependent name on T, which kind of "postponed" the ​name lookup to the point of instantiation.

On the contrast, for struct B : A<int>, using type2 = type works totally fine since A<int> is explicitly instantiated so that A<int>::type is visible from the template definition context.

Hy Zhou
  • 1
  • 1