3

I ran into this situation when trying to run down a subtle bug in some code.

template<typename T>
struct S
{
   int f(){ return this->r; }
   int g(){ return r; }
};

The compiler flags an error on the definition of S::g, even when I never instantiate a specialization of the template, which is actually what I expected: The name r is unqualified and is not declared anywhere in scope.

What puzzles me is that an error is not flagged on the definition of S::f until I instantiate a specialization, say, CT<int>f, and call its f.

In other words, it seems like the compiler regards this as a pointer to a dependent type instead of a pointer to the current instantiation.

Is this correct? (My compiler is g++ 8.1.0). If g++ is doing the right thing, can you explain it?

  • I'm pretty sure it's normal. Since `this` does not have a type until T is defined, the evaluation of `this->` is deferred. –  Dec 13 '19 at 22:44
  • I normally expect a diagnostic when template code contains a construct that cannot possibly be well-formed no matter what types are substituted for the template type parameters. That seems to be the case here; what am I missing? How can ``this`` point to anything but the current instantiation? And the current instantiation has no member r. Or is it simply that the standard doesn't require a diagnostic at this point and it's too tricky to check such cases? – Kent G. Budge Dec 13 '19 at 22:48
  • [two-phase-lookup-explanation-needed](https://stackoverflow.com/questions/7767626/two-phase-lookup-explanation-needed) might interest you. – Jarod42 Dec 13 '19 at 22:51
  • @Kent Think like a compiler. if I see `a->b`, I will lookup the type of `a`, and see if that type has a member `b`. However, while **parsing** the template, `this` has no type to speak of. Sure, the compiler could have a special rule to handle that specific scenario, but there are soooo many more cases to consider here. What if `r` is of type `T`? wjhat if S inherits from `U`? Is it really worth having an exceptional rule for that one specific scenario? –  Dec 13 '19 at 22:52
  • The only case I can think of where ``this`` would refer to a specialization of ``S`` that has a member ``r`` is if a specialization of ``S`` somehow retains the original definition of ``f()``. Otherwise, doesn't the specialization have to define its own ``f()``? I have a feeling I'm about to learn something subtle about C++ here ... – Kent G. Budge Dec 13 '19 at 22:59
  • Incidentally, @Frank, "It's a special enough case to not be work diagnosing, even if we could" is an acceptable answer, if correct. – Kent G. Budge Dec 13 '19 at 23:11

1 Answers1

1

There are two types of template code. You have dependent and non dependent code, that is code that depends on a template parameter and code that doesn't. In

int g(){ return r; }

There is nothing that depends on T so the compiler checks out the code, see's it's not valid and you get an error.

In

int f(){ return this->r; }

r now depends on T because this depends on T. Since you can't know if it is valid or not until you know what T is, the code is "ignored" and you only get an error once it's actually instantiated.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • As I said, I understand the first case. What puzzles me in the second is that ``this`` doesn't depend on T, not really; it refers to the current instantation, which we know has no member r no matter what T is. – Kent G. Budge Dec 13 '19 at 22:49
  • @KentG.Budge I know, but answers aren't just for the original poster but also for others that come later. I'm trying to cover all the bases in case they don't understand. – NathanOliver Dec 13 '19 at 22:51
  • @KentG.Budge While true, the rules aren't that complex. `this` can change depending on `T` (there could be specializations) so the name is dependent and lookup is deferred until the template is instantiated. – NathanOliver Dec 13 '19 at 22:53