Andrey Nekrasov
Andrey Nekrasov

Reputation: 466

using typename from template parameter in class

//A.h
template <class T>
class A
{
public:
    typename T::Type x; //(1) compile time error: C2039 'Type': is not a member of 'B'
    void f();
};
template <class T>
void A<T>::f() 
{ 
  typename T::Type x1; //(2) but no errors here
}

//B.h 
#include "A.h"

class B : public A<B>
{
public:
    using Type = int;
};

//main.cpp
#include "B.h"

int main()
{
    B x;
}

Why there is error in (1) but no errors in (2)? How can I store a variable of type typename T::Type and write function like func(typename T::Type) in A class?

I don't know why this class design was done and I don't want to change class hierarchy or template parameters in code because there are a lot of classes inherited from A and code is quite confusing. So please no advices in this way.

P.S. Sorry for not clear question name, but I cannot invent better one.

Upvotes: 0

Views: 73

Answers (3)

molbdnilo
molbdnilo

Reputation: 66371

You can't do that due to circularity in definitions - A<B> can't be defined until B is defined, and B can't be defined until A<B> is defined.

What you can do is add a level of indirection, going through a "traits" class that's independent of the ultimate definition of B.

Example:

template <typename T>
struct traits{};

template <class T>
class A
{
public:
    typename traits<T>::Type x; 
};

class B;

template <>
struct traits<B>
{
    using Type = int;
};

class B : public A<B>
{
public:
    using Type = typename traits<B>::Type;
};


int main()
{
    B x;
}

Upvotes: 0

Klaus
Klaus

Reputation: 25603

While you are define class B : public A<B> the class B is not defined but you try to use this class in A. At this point of time, the compiler has no knowledge if there will be a definition of using Type = int;.

gcc provides a more readable error message: "invalid use of incomplete type 'class B'"

void A<T>::f() will never be instantiated, so you will not see an error message.

The bad news: You have no chance to do any kind of forward declaration in this situation as you have a full circular dependency.

Upvotes: 3

n. m. could be an AI
n. m. could be an AI

Reputation: 119857

class B : public A<B>

B is incomplete at this point. It is not known yet that it has a Type member. So instantiation of A::x fails.

By contrast, A<T>::f() is never instantiated. If you do instantiate it, it is likely to happen when B is a complete type, so B::Type should already be known.

Upvotes: 1

Related Questions