Problem with template using base class template in GCC

W

Walt Karas

The following gives an error in the declaration of the
member function x() of the class template Tpl, compiliing
with a recent version of GCC under Solaris:

class A { };
class B { };

template <typename Base>
class Tpl : protected Base
{
public:
template <typename AOrB>
int x(void) { return(baseX<AOrB>()); }
};

class TheBase
{
public:

template<typename AOrB>
int baseX(void);
};

template<>
inline int TheBase::baseX<A>(void) { return(1); }

template<>
inline int TheBase::baseX<B>(void) { return(2); }

Tpl<TheBase> aTpl;

But if I give 'baseX' a dummy parameter whose type is the type parameter
to the template, making explicit naming of the type paramenter in the
baseX call unecessary, it does compile:

class A { };
class B { };

template <typename Base>
class Tpl : protected Base
{
public:
template <typename AOrB>
int x(void) { return(baseX(AOrB())); }
};

class TheBase
{
public:

template<typename AOrB>
int baseX(AOrB aOrB);
};

template<>
inline int TheBase::baseX<A>(A a) { return(1); }

template<>
inline int TheBase::baseX<B>(B b) { return(2); }

Tpl<TheBase> aTpl;

Is there some rule in the standard that requires this behavior?
Or is this just a problem with the GCC compiler?

Another thing that surprised me was that GCC gives me an error if
I put the partial specializations of 'baseX' inside the declaration
of the class 'TheBase'.
 
V

Victor Bazarov

Walt Karas said:
The following gives an error in the declaration of the
member function x() of the class template Tpl, compiliing
with a recent version of GCC under Solaris:

class A { };
class B { };

template <typename Base>
class Tpl : protected Base
{
public:
template <typename AOrB>
int x(void) { return(baseX<AOrB>()); }

I got it to compile by doing this:

template <typename AOrB>
inx x() { return this->template baseX said:
};

class TheBase
{
public:

template<typename AOrB>
int baseX(void);
};

template<>
inline int TheBase::baseX<A>(void) { return(1); }

template<>
inline int TheBase::baseX<B>(void) { return(2); }

Tpl<TheBase> aTpl;

But if I give 'baseX' a dummy parameter whose type is the type parameter
to the template, making explicit naming of the type paramenter in the
baseX call unecessary, it does compile:

class A { };
class B { };

template <typename Base>
class Tpl : protected Base
{
public:
template <typename AOrB>
int x(void) { return(baseX(AOrB())); }
};

class TheBase
{
public:

template<typename AOrB>
int baseX(AOrB aOrB);
};

template<>
inline int TheBase::baseX<A>(A a) { return(1); }

template<>
inline int TheBase::baseX<B>(B b) { return(2); }

Tpl<TheBase> aTpl;

Is there some rule in the standard that requires this behavior?

Yes, if the base class depends on the template type, its scope is not
searched to resolve a dependent name.
Or is this just a problem with the GCC compiler?

I don't think so. Comeau also rejected the first example.
Another thing that surprised me was that GCC gives me an error if
I put the partial specializations of 'baseX' inside the declaration
of the class 'TheBase'.

That's also still prohibited. They are thinking of adding it to the
next Standard, IIRC.

V
 
P

Paul

Victor Bazarov said:
I got it to compile by doing this:

template <typename AOrB>


Yes, if the base class depends on the template type, its scope is not
searched to resolve a dependent name.


I don't think so. Comeau also rejected the first example.


That's also still prohibited. They are thinking of adding it to the
next Standard, IIRC.

V

Firstly I'd like to say that it compiles ok with MS 2003 Compiler.

I believe it should compile ok as I can see nothing wrong with the
code.
But the point made about name lookup , I have read too that base
templates are not searched but in this case we have the rules of
inheritance do we not. You could also try to call the base funtion
with fully qualified name which also worked for me but was not
required i.e: theBase::baseX<T>(T b);.
Try making your inheritance public then you should be able to call
baseX directly from instances of Tpl.
I don't think it would be very good if templating a class meant we
lost the inheritance, so I believe it's a fault with your compiler.

And also you are speaking of partial specialization but this is not
partial specialization it's full specialization of member function
baseX. I'm not sure on all the rules but I can define them within the
class and it works fine. And I don't see why you shouldn't be able too
do so. I think member function specializations are generally defined
out of class for clarity though.

HTH Paul
 
V

Victor Bazarov

Paul said:
[...]
Firstly I'd like to say that it compiles ok with MS 2003 Compiler.

[...]
I'm not sure on all the rules but I can define them within the
class and it works fine. [...]

Have you tried turning "language extensions" off?

Here is the rule of comp.lang.c++: if it compiles with your compiler,
it's not enough to confirm that the code is standard C++. Try to
follow it. To help you develop a sense of right and wrong WRT C++
language, get a copy of the Standard document.

V
 
W

Walt Karas

Victor Bazarov said:
Paul said:
[...]
Firstly I'd like to say that it compiles ok with MS 2003 Compiler.

[...]
I'm not sure on all the rules but I can define them within the
class and it works fine. [...]

Have you tried turning "language extensions" off?

Here is the rule of comp.lang.c++: if it compiles with your compiler,
it's not enough to confirm that the code is standard C++. Try to
follow it. To help you develop a sense of right and wrong WRT C++
language, get a copy of the Standard document.

V

Another good rule would be to cite a particular paragraph in
the standard when saying that something isn't compliant, if
at all possible.

Why would it be desirable to impose this limitation? Does
the compiler need to bind the referenced template to a definition
visible in the scope where the refering template is being
defined (in order to make instantiation context-independent)?
Seems like the compiler could just assume the template was
in the base class, then enforce this assumption at
instantiation. Or, if that's too hard, require the previously
posted suggestion of a base:: qualifier on the template.
 
P

Paul

Victor Bazarov said:
Paul said:
[...]
Firstly I'd like to say that it compiles ok with MS 2003 Compiler.

[...]
I'm not sure on all the rules but I can define them within the
class and it works fine. [...]

Have you tried turning "language extensions" off?

Here is the rule of comp.lang.c++: if it compiles with your compiler,
it's not enough to confirm that the code is standard C++. Try to
follow it. To help you develop a sense of right and wrong WRT C++
language, get a copy of the Standard document.

V

Another good rule would be to cite a particular paragraph in
the standard when saying that something isn't compliant, if
at all possible.

Why would it be desirable to impose this limitation? Does
the compiler need to bind the referenced template to a definition
visible in the scope where the refering template is being
defined (in order to make instantiation context-independent)?
Seems like the compiler could just assume the template was
in the base class, then enforce this assumption at
instantiation. Or, if that's too hard, require the previously
posted suggestion of a base:: qualifier on the template.

I needed to use qualified names with extensions turned off i.e:

return this->baseX<AOrB>();
return Base::baseX<AOrB>();

Both these work for me but I'm still unsure if the second is completely correct.


Here is a link about it:
http://www.tempest-sw.com/cpp/draft/ch07-templates.html
Near the bottom of the page it's explained under Resolving names.

Paul.
 
G

Gilles Rochefort

template<>
inline int TheBase::baseX<A>(void) { return(1); }

template<>
inline int TheBase::baseX<B>(void) { return(2); }

Tpl<TheBase> aTpl;

But if I give 'baseX' a dummy parameter whose type is the type parameter
to the template, making explicit naming of the type paramenter in the
baseX call unecessary, it does compile:

Well, I'm not sure to understand what you want to do here ????
But, from what you wrote, I guess that the compiler interpret the two
specialized functions as two more functions in the class TheBase.
Unfortunately, you don't explicitely make use of either class A or
either class B,so the compiler can't decide wich one to choose.

class TheBase
{
public:

template<typename AOrB>
int baseX(AOrB aOrB);
};

template<>
inline int TheBase::baseX<A>(A a) { return(1); }

template<>
inline int TheBase::baseX<B>(B b) { return(2); }

Tpl<TheBase> aTpl;

Here, as you provide two functions with different input arguments,
compiler can now assign two functions to TheBase that are :
int TheBase::baseX(A a);
int TheBase::baseX(B b);

This is a common overloading rule. Remember, you can't overload function
with the same argument.
Another thing that surprised me was that GCC gives me an error if
I put the partial specializations of 'baseX' inside the declaration
of the class 'TheBase'.

Because of c++ doesn't allow template specializations inside a class ...
More exactly specialized template should be associated with a namespace
scope.

Hope, all this will help !
Probably if you tell more about what you want to do exactly, I should help
you a bit more.

Best regards,
Gilles Rochefort
 
C

Chris Vine

Walt said:
The following gives an error in the declaration of the
member function x() of the class template Tpl, compiliing
with a recent version of GCC under Solaris:

class A { };
class B { };

template <typename Base>
class Tpl : protected Base
{
public:
template <typename AOrB>
int x(void) { return(baseX<AOrB>()); }
^^^^^^^^^^^^^^^^^^^^^^
(See below)
};

class TheBase
{
public:

template<typename AOrB>
int baseX(void);
};

template<>
inline int TheBase::baseX<A>(void) { return(1); }

template<>
inline int TheBase::baseX<B>(void) { return(2); }

Tpl<TheBase> aTpl;

[snip]

I have had to change quite a lot of code of this kind to compile with
gcc-3.4. According to gcc-3.4, the syntax for your call in int Tpl::x() to
a method in the templated base class is:

int x(void) { return(Base::baseX<A0rB>()); }
^^^^^^
In other words, you need to specify that baseX() is a member of the
templated base class. Whether that is required by the standard I know not,
but I expect it is right. gcc-3.4 is a lot stricter than gcc-3.2/3.3.

You have set follow-ups to a group I do not read, so I will not see any
response (not a very good idea).

Chris.
 
P

Paul

Because of c++ doesn't allow template specializations inside a class ...
More exactly specialized template should be associated with a namespace
scope.

Are you sure about that?

class Test{
public:
template<typename T>void foo(T){}
template<>void foo(double){}
};

The above compiles ok , not saying that means it's right, but are you
ssaying this is not allowed? Is the namespace for foo here not Test?
 
V

Victor Bazarov

Paul said:
Are you sure about that?

class Test{
public:
template<typename T>void foo(T){}
template<>void foo(double){}
};

The above compiles ok , not saying that means it's right, but are you
ssaying this is not allowed? Is the namespace for foo here not Test?

How many times do we have to write, "'compiles ok', doesn't necessarily
mean 'correct code'"? Try to remember that and avoid "hey, it compiles
OK on my compiler so it must be good code".
 
O

Old Wolf

Victor Bazarov said:
I got it to compile by doing this:

template <typename AOrB>
inx x() { return this->template baseX<AOrB>(); }

To elaborate: firstly, baseX is a dependent name because it
depends on 'Base'. The compiler doesn't look in dependent
base classes to resolve names. So you have go this-> or Base::
to tell the compiler where it is.

Secondly, it doesn't know what the symbol 'baseX' is at this
point. In particular it could be : int baseX; in which case
baseX<AOrB> is parsed as baseX (less-than operator) AOrB
(syntax error). So the keyword 'template' indicates that
baseX is the name of a template member function.
 
G

Gilles Rochefort

class Test{
public:
template<typename T>void foo(T){}
template<>void foo(double){}
};

Yes, as I said this not allowed ...
The above code don't compile on a recent gcc ( I tested on a 3.3.2 )
I guess that gcc becomes lesser and lesser permissive ..

So, now you have to write the following code to get a chance to compile.

class Test{
public:
template<typename T>void foo(T){}
};

template<>void Test::foo(double){}

Gilles.
 
S

Sharad Kala

Paul said:
Are you sure about that?

class Test{
public:
template<typename T>void foo(T){}
template<>void foo(double){}
};

Yes, he is correct. The relevant section in standard is 14.7.3/2: "An
explicit specialization shall be declared in the namespace of which the
template is a member, or, for member templates, in the namespace of which
the enclosing class or enclosing class template is a member."

-Sharad
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top