1

I was trying to integrate the boost::share_ptr into a pair of templated classes that were originally derived from a boost::asio example I found. When I define a type within one class which is a shared::ptr of that class. I can't seem to reference the type in another templated class. If I remove templates from the code, it all compiles.

This won't compile:

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace std;

template <typename TSomething1>
class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT<TSomething1> >
{
public:
    typedef boost::shared_ptr<SomeTemplateT<TSomething1> > Ptr;

    static Ptr Create()
    {
        return Ptr(new SomeTemplateT<TSomething1>());
    }

    SomeTemplateT()
    {
        cout << "SomeTemplateT created" << endl;
    }
};

template <typename TSomething>
class OtherTemplateT
{
public:
    OtherTemplateT()
    {
        // COMPILATION ERROR HERE
        SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create(); 
    }

private:

};

The code above yields the following compilation error:

src\Templates\main.cpp: In constructor 'OtherTemplateT<TSomething>::OtherTemplateT()':
src\comps\oamp\src\Templates\main.cpp:30: error: expected ';' before 'someTemplate'

Taking virtually the same code without templates compiles without difficulty:

class SomeTemplateT : public boost::enable_shared_from_this<SomeTemplateT>
{
public:
    typedef boost::shared_ptr<SomeTemplateT> Ptr;

    static Ptr Create()
    {
        return Ptr(new SomeTemplateT());
    }

    SomeTemplateT()
    {
        cout << "SomeTemplateT created" << endl;
    }
};

class OtherTemplateT
{
public:
    OtherTemplateT()
    {
        SomeTemplateT::Ptr someTemplate = SomeTemplateT::Create();
    }

private:

};

Platform information: I'm using gcc4.4.0 from MinGW on windows XP (Code:Blocks IDE).

Am I doing something wrong?

EDIT: I forgot to mention that if I replace the use of the Ptr typedef with the full declaration of the shared ptr: boost::shared_ptr Everything compiles fine.

Also, I can use the type in code outside the of the template.

Lou
  • 1,955
  • 14
  • 16
  • 2
    possible duplicate of [Where and why do I have to put the "template" and "typename" keywords?](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) – Mike Seymour Jan 23 '12 at 15:38

3 Answers3

4

SomeTemplateT<TSomething>::Ptr is a dependent name; that is, its definition depends on the template parameter. The compiler can't assume that it's a type name unless you say so:

typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();
^^^^^^^^
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • That did it. I have to remember that everytime I get these bizarre errors, throw in typename :-) – Lou Jan 23 '12 at 15:46
  • 1
    @Lou: It's actually very predictable when you'll get those errors. If the name of a type has a template parameter, use `typename`. – Drew Dormann Jan 23 '12 at 16:37
3

You need to use typename:

typename SomeTemplateT<TSomething>::Ptr someTemplate = SomeTemplateT<TSomething>::Create();

This is required to make parsing possible without semantic analysis. Whether SomeTemplateT<TSomething>::Ptr is a type or a member is not known until SomeTemplateT<TSomething> has been compiled.

Magnus Hoff
  • 21,529
  • 9
  • 63
  • 82
1

A example taken from the C++11 Standard (n3290) that demonstrate why the keyword typename (in this context) is useful. ( 14.6 Name resolution [temp.res] )

struct A 
{
    struct X { };
    int X;
};

struct B 
{
    struct X { };
};

template<class T> void f(T t) 
{
    typename T::X x;
}

void foo() 
{
    A a;
    B b;
    f(b); // OK: T::X refers to B::X
    f(a); // error: T::X refers to the data member A::X not the struct A::X
}