Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem with (simple) use of templates

34 views
Skip to first unread message

scott....@gmail.com

unread,
Jun 27, 2017, 12:06:07 PM6/27/17
to
I'm checking to see if my understanding of C++ is correct. I've run into problems compiling code under g++ and I'm trying to decide if the problem is mine or g++'s. This wasn't supposed to be complicated...

In a header, I have a templated class as a parent class. Relevant excerpts:

template<int Size_>
class Buffer {
public:
.....
bool overflowed_; //public
....};

//And then I want to base off it with:

template<int Size_>
class OutputBuffer : public Buffer<Size_>
{
public:
....

OutputBuffer() : Buffer<Size_>() { }
....
void doSomething() { if (overflowed_) {....} } //problems!
};

This looks straightforward to me. But for g++ at least, overflowed_, and every other reference to any function or data in Buffer, apparently needs to be qualified with Buffer<Size_>::. This seems especially odd for overflowed_, which doesn't participate in the parameterization of the parent's template. But that shouldn't matter. It's a parent class with public members and it should not matter that it's also templated.

Note the compile isn't failing on an instantiation. It fails as soon as the compiler parses the header, before any instantiation is attempted.

This makes no sense to me. OutputBuffer is based on a type, and the type is specified by the parent class syntax " : public Buffer<Size_>". When the time comes to instantiate, that parent class will have a definitive definition, but even before that, it seems to be that C++ specifies that the compiler has enough visibility into the subclass to know exactly what I'm referring to. The parent class should be "specified enough" at that point.

Other compilers have accepted this, so now I'm trying to determine if this is my problem or g++'s. I can work around it by adding Buffer<Size_>:: everywhere, but that's not how subclassing is supposed to work. (Note I can't avoid g++ - eventually this code is going to a platform where it's likely g++ or nothing.)

Insight into why C++ doesn't promise what I want, is welcome. This has messed with my understanding of how templates work.

Paavo Helde

unread,
Jun 27, 2017, 1:15:29 PM6/27/17
to
On 27.06.2017 19:05, scott....@gmail.com wrote:
> I'm checking to see if my understanding of C++ is correct. I've run into problems compiling code under g++ and I'm trying to decide if the problem is mine or g++'s. This wasn't supposed to be complicated...
>
> In a header, I have a templated class as a parent class. Relevant excerpts:
>
> template<int Size_>
> class Buffer {
> public:
> .....
> bool overflowed_; //public
> ....};
>
> //And then I want to base off it with:
>
> template<int Size_>
> class OutputBuffer : public Buffer<Size_>
> {
> public:
> ....
>
> OutputBuffer() : Buffer<Size_>() { }
> ....
> void doSomething() { if (overflowed_) {....} } //problems!
> };
>
> This looks straightforward to me. But for g++ at least, overflowed_, and every other reference to any function or data in Buffer, apparently needs to be qualified with Buffer<Size_>::. This seems especially odd for overflowed_, which doesn't participate in the parameterization of the parent's template. But that shouldn't matter. It's a parent class with public members and it should not matter that it's also templated.

The idiomatic way to fix this is:

void doSomething() { if (this->overflowed_) {....} }

See

https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members

In short, there is no problem with gcc here, but there is a problem with
either your code or possibly with the C++ standard itself if the FAQ
needs to contain such usage warnings as "This might hurt your head!"


Öö Tiib

unread,
Jun 27, 2017, 1:48:08 PM6/27/17
to
On Tuesday, 27 June 2017 20:15:29 UTC+3, Paavo Helde wrote:
> On 27.06.2017 19:05, scott....@gmail.com wrote:
> > I'm checking to see if my understanding of C++ is correct. I've run into problems compiling code under g++ and I'm trying to decide if the problem is mine or g++'s. This wasn't supposed to be complicated...
> >
> > In a header, I have a templated class as a parent class. Relevant excerpts:
> >
> > template<int Size_>
> > class Buffer {
> > public:
> > .....
> > bool overflowed_; //public
> > ....};
> >
> > //And then I want to base off it with:
> >
> > template<int Size_>
> > class OutputBuffer : public Buffer<Size_>
> > {
> > public:
> > ....
> >
> > OutputBuffer() : Buffer<Size_>() { }
> > ....
> > void doSomething() { if (overflowed_) {....} } //problems!
> > };
> >
> > This looks straightforward to me. But for g++ at least, overflowed_, and every other reference to any function or data in Buffer, apparently needs to be qualified with Buffer<Size_>::. This seems especially odd for overflowed_, which doesn't participate in the parameterization of the parent's template. But that shouldn't matter. It's a parent class with public members and it should not matter that it's also templated.
>
> The idiomatic way to fix this is:
>
> void doSomething() { if (this->overflowed_) {....} }

Other way to fix this is to bring the member into scope:

using Buffer<Size_>::overflowed_;

void doSomething() { if (overflowed_) {....} }
>
> See
>
> https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members
>
> In short, there is no problem with gcc here, but there is a problem with
> either your code or possibly with the C++ standard itself if the FAQ
> needs to contain such usage warnings as "This might hurt your head!"

Simpler is just to live with yet another gotcha that
standard requires name overflowed_ to be looked-up in a
base classes, but not in dependent templates of base classes and
to hope that it makes life easier for compiler-makers somehow.

scott....@gmail.com

unread,
Jun 27, 2017, 1:51:53 PM6/27/17
to
On Tuesday, June 27, 2017 at 1:15:29 PM UTC-4, Paavo Helde wrote:
...
> The idiomatic way to fix this is:
>
> void doSomething() { if (this->overflowed_) {....} }
>
> See
>
> https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members
>
> In short, there is no problem with gcc here, but there is a problem with
> either your code or possibly with the C++ standard itself if the FAQ
> needs to contain such usage warnings as "This might hurt your head!"

Wow. Yes it worked. I've never come across a situation where this-> was required anywhere. Live and learn, thanks.

Alf P. Steinbach

unread,
Jun 27, 2017, 2:02:31 PM6/27/17
to
It matters because the `Buffer` class can be specialized for some
template parameter values, and those specialization will not necessarily
have the `overflowed_` member, or whatever.

We say that these expressions /depend/ on the template parameters.

A good way to deal with it is to add

using Base = Buffer<Size_>;
using Base::overflowed_;

Or you can qualify each usage, which is at odds with the principle of
not repeating yourself needlessly.

Visual C++ is more lenient because it follows the pre-standard single
phase template parsing rules (disclaimer: I no longer remember the
details of this, I'd have to look it up). I.e. g++ is more conforming
and hence, IMO., more impractical. For I can't remember any single
occasion where this required nonsense verbosity has saved my code from
being incompatible with a nasty specialization of a base class template.




> [snip]

Cheers & hth.,

- Alf

Scott Lurndal

unread,
Jun 27, 2017, 2:08:57 PM6/27/17
to
Another place where this-> is required is with member function pointers:

e.g.

bool (c_processor::*op_insn)(struct _op *);

...

// Process the instruction
failed = (this->*opp->op_insn)(opp);

Richard

unread,
Jun 27, 2017, 3:18:40 PM6/27/17
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<oiu6bu$qd1$1...@dont-email.me> thusly:

>We say that these expressions /depend/ on the template parameters.
>
>A good way to deal with it is to add
>
> using Base = Buffer<Size_>;
> using Base::overflowed_;
>
>Or you can qualify each usage, which is at odds with the principle of
>not repeating yourself needlessly.

I like this as the minimal change needed to resolve the problem. Can
we do better?

What if we move everything that isn't dependent on the template
parameters into a separate base class? This would be a base class
of Buffer<N>:

class BufferBase
{
public:
bool overflowed_;
// ...
};

template <int Size_>
class Buffer : public BufferBase
{
// ...
};

I like this better because it disambiguates the references to
overflowed_ without any using statements in derived classes. It also
clearly separates everything that depends on template parameters from
everything that doesn't which I think makes for a cleaner design.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Richard

unread,
Jun 27, 2017, 3:19:11 PM6/27/17
to
[Please do not mail me a copy of your followup]

scott....@gmail.com spake the secret code
<2d9dc958-d374-40a0...@googlegroups.com> thusly:

>Wow. Yes it worked. I've never come across a situation where this-> was
>required anywhere. Live and learn, thanks.

It isn't required, it is simply one way (of several) to resolve the
ambiguity.
0 new messages