Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a nested typedef in a template?

Tags:

c++

templates

I want to derive a type Test from a templated type Base which I specialise on the derived type (i.e. Base<Test>).

Inside the templated type, I want to make use of a typedef defined in the derived type (the template parameter).

However, I get this compile error:

error C2039: 'X' : is not a member of 'Test'

Here is the code snippet:

template <typename T>
class Base
{
protected:
  void func(typename T::X x) {}
};


class Test : public Base<Test>
{
public:
  typedef int X;
};

Is this doable, and if so, what is the fix I need to make?

(I see a couple of answers for this kind of problem but it looks like my scenario isn't fixed by prefixing typename - is it something to do with deriving from a template specialised with the derived type?)

like image 236
mackenir Avatar asked Mar 12 '15 16:03

mackenir


4 Answers

Alternatively to the typedef, you can also declare the type as second template argument in the base class:

template <typename T, typename X>
class Base
{
protected:
  void func(X x) {}
};


class Test : public Base<Test, int>
{
public:
//  typedef int X;
};
like image 94
Alexander Giesler Avatar answered Nov 09 '22 22:11

Alexander Giesler


This works for me:

template <typename T> struct Traits;

template <typename Derived>
class Base
{
   protected:
      void func(typename Traits<Derived>::X x) {}
};


class Test;

template <> struct Traits<Test>
{
  typedef int X;
};


class Test : public Base<Test>
{
};
like image 1
R Sahu Avatar answered Nov 09 '22 22:11

R Sahu


I'm not sure about this behavior, maybe someone can clarify it. But as I understand by the moment you do : public Base<Test> the type name X doesn't exists (since is declared below).

If you create a wrapper class before making the inheritance the type would exists by the moment you do the inheritance and the template instantiation will work.

This compiles with VC++ 2013

template <typename T>
class Base
{
protected:
    void func(typename T::X x) {}
};


class TestWrapper
{
public:
    typedef int X; //Declared, now it exists for the compiler
};

class Test
    :public Base<TestWrapper> //Compiles correctly
{

};
like image 1
felknight Avatar answered Nov 10 '22 00:11

felknight


You have a circularity which cannot be resolved with forward declarations. But this will work, although (I suspect) not quite so strongly defined as you wanted.

template <typename T>
class Base
{
protected:
    template<typename Y>
    void func(Y x) {}
};

class Test : public Base<Test>
{
public:
    typedef int X;
};

If func were public, then you could then write

Test t;
Test::X x;
t.func(x)

which is satisfactory for any use of the Curiously Recurring Template Pattern I think of.

like image 2
Bathsheba Avatar answered Nov 09 '22 23:11

Bathsheba