简体   繁体   中英

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.

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

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.

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.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM