8

Possible Duplicate:
GCC problem : using a member of a base class that depends on a template argument

I thought I was familiar with C++, but apparently not familiar enough.
The problem is when you define a constant in a template class, you can use the constant in new classes that derive from that class, but not new template classes that derive from it.

For example, gcc says

test.h:18: error: ‘theconstant’ was not declared in this scope

when I try to compile this (simplified) header file:

#pragma once

template <typename T> class base
{
  public:
    static const int theconstant = 42;
};

class derive1 : public base<size_t>
{
  public:
    derive1(int arg = theconstant) {}
};

template<typename T> class derive2 : public base<T>
{
  public:
    derive2(int arg = theconstant) {} // this is line 18
};

So the problem is that one class, derive1, compiles fine, but the other class, derive2, which is a template specialisation, does not.
Now maybe gcc's error is not clear enough, but I don't understand why the constructor in derive2 would have a different scope than the one in derive1.
In case it matters, this happens during compilation of the header file itself, not when instantiating an object of type derive2<type>.

I also know what to change to make this compile, so I'm not really looking for one-line pieces of code as answers. I want to understand why this happens! I tried searching the web, but apparently I'm not using the correct search arguments.

Community
  • 1
  • 1
Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • FWIW, this same code compiles fine in VC++ 2010. This might be a bug in GCC... – dsharlet Jul 01 '12 at 21:28
  • `derive2(int arg = base::theconstant) {}` compiles fine. – jrok Jul 01 '12 at 21:29
  • @dsharlet - not a bug on GCC's part, as described in the spec. – Flexo Jul 01 '12 at 21:29
  • @BoPersson Thanks for pointing me to the other question. But I still don't understand completely. What can go wrong if the compiler simply fetches the original identifier silently? Can you (or anybody) provide an example of where that would go wrong? – Mr Lister Jul 01 '12 at 21:36
  • @jrok I know! But what I want to understand is why this is deemed necessary in derived2 and not in derived1, even if the inheritance is not ambiguous. – Mr Lister Jul 01 '12 at 21:40
  • It goes very wrong if there are specializations of the base template without `theconstant` and also global objects with the same name. The standard says that we cannot assume that `theconstant` depends on `T` unless you say so. `base::theconstant` or `this->theconstant` are ways of doing that. – Bo Persson Jul 01 '12 at 21:44
  • @dsharlet: Actually a deviation from the standard in VS (does not perform two phase lookup properly). – David Rodríguez - dribeas Jul 01 '12 at 23:23

2 Answers2

2

Try

template<typename T> class derive2 : public base<T>
{
  public:
    derive2(int arg = base<T>::theconstant) {} // this is line 18
};

Basically you've specified the incomplete scope for the "theconstant".

Viktor Latypov
  • 14,289
  • 3
  • 40
  • 55
  • Yeah, that was mentioned in the comments. But what I want to understand is why this is deemed necessary in `derived2` and not in `derived1`, even if the inheritance is not ambiguous. In what way is the scope incomplete? – Mr Lister Jul 01 '12 at 21:42
  • 1
    I guess it has to do something with the "lazy" template instantiation. There is _no_ 'base' class known to the compiler at the time it parses 'theconstant' in derive2. Once you use the base, you force compiler to "get familiar" with the base<> – Viktor Latypov Jul 01 '12 at 21:46
  • I'll have to think about this. – Mr Lister Jul 01 '12 at 22:07
2

I am pretty sure this will help you understand:

Your code which does not compile:

template<typename T> class derive2 : public base<T>
{
  public:
    derive2(int arg = theconstant) {} // this is line 18
};

And the reason why:

template <> class base<size_t>
{
  public:
    static const int ha_idonthave_theconstant = 42;
};
derive2<size_t> impossible_isnt_it; 

The specialization!!! Compiler at your line 18 cannot be sure that you will not specialize the base<> in the way that this constant will not be present there at all.

PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • That makes so much sense that I wonder why it didn't occur to me... I did try with a specialised template, only containing the same member with a different value, and I couldn't make it not work. Oh well. Thanks! – Mr Lister Jul 02 '12 at 08:00