7

GCC 4.4.1 is refusing to find my injected-class-name within a ctor-initializer:

template <typename T>
struct Base
{
    Base(int x) {}
};

struct Derived : Base<int>
{
    Derived() : Base(2) {}
};

int main()
{
    Derived d;
}
test2.cpp: In constructor "Derived::Derived()":
test2.cpp:9: error: class "Derived" does not have any field named "Base"
test2.cpp:9: error: no matching function for call to "Base<int>::Base()"
test2.cpp:4: note: candidates are: Base<T>::Base(int) [with T = int]
test2.cpp:3: note:                 Base<int>::Base(const Base<int>&)

GCC 4.8 compiles it just fine, though.

I'm sure this is supposed to work, and I can't find any standard wording that disagrees with me.

This a GCC 4.4.1 bug, right?

(I did scour GCC Bugzilla but nothing relevant popped out at me.)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Can you use `Base` outside of the constructor? Maybe GCC 4.4 thinks `Base` is a dependant name. – Simple Jan 14 '14 at 16:34
  • 3
    Not sure, but looks somewhat similar to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45515 – BoBTFish Jan 14 '14 at 16:34
  • @Simple: Nope - even this fails: http://coliru.stacked-crooked.com/a/23d997547aa80bab. So I suppose I could have abstracted out the _ctor-initializer_ too! – Lightness Races in Orbit Jan 14 '14 at 16:36
  • @BoBTFish: That looks like the one. – Lightness Races in Orbit Jan 14 '14 at 16:37
  • 1
    @Simple: `Derived` is not a template, `Base` cannot be dependent on any template argument – David Rodríguez - dribeas Jan 14 '14 at 16:37
  • 1
    @DavidRodríguez-dribeas I'm aware, that's why it's a bug. GCC might think it is. You could test `typename Derived::Base` to see if this is the problem. – Simple Jan 14 '14 at 16:37
  • 2
    Just tried to compile it with a few: GCC 4.4.0 : failed GCC 4.4.1 : failed GCC 4.4.2 : failed GCC 4.4.3 : failed GCC 4.4.4 : failed GCC 4.4.5 : failed GCC 4.4.6 : failed GCC 4.4.7 : failed GCC 4.5.0 : success GCC 4.5.1 : success GCC 4.5.2 : success GCC 4.5.3 : success GCC 4.5.4 : success GCC 4.6.0 : success GCC 4.6.1 : success GCC 4.6.2 : success GCC 4.6.3 : success GCC 4.7.0 : success GCC 4.7.1 : success GCC 4.7.2 : success GCC 4.7.3 : success GCC 4.8.0 : success GCC 4.8.1 : success GCC 4.8.2 : success – PlasmaHH Jan 14 '14 at 16:48
  • @PlasmaHH: Ahhhhh where were you an hour ago when I wanted to ask you to do that :D – Lightness Races in Orbit Jan 14 '14 at 16:51

2 Answers2

4

Yeah, it is a bug.

I can reproduce it even more simply without the ctor-initialiser:

template <typename T>
struct Base
{
};

struct Derived : Base<int>
{
    Base* ptr;
};

int main()
{
    Derived d;
}

/**
 * in GCC 4.4.1:
 * 
 * error: ISO C++ forbids declaration of "Base" with no type
 */

And:

[C++11: 14.6.1/4]: A lookup that finds an injected-class-name (10.2) can result in an ambiguity in certain cases (for example, if it is found in more than one base class). If all of the injected-class-names that are found refer to specializations of the same class template, and if the name is used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous. [ Example:

template <class T> struct Base { };
template <class T> struct Derived: Base<int>, Base<char> {
   typename Derived::Base b;            // error: ambiguous
   typename Derived::Base<double> d;    // OK
};

—end example ]

Notice that the near-equivalent of my unambiguous usage is "OK". Alright, so Derived is a class template here and not in my example, so it's not quite the same example. But I'm satisfied now that the entirety of 14.6.1 makes my code legal.

Turns out it had been raised as GCC bug 45515, but since it had been fixed on head at the time there are very few details on it.

Thanks BoBTFish!

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

Use : Base<int>(2) {}

(edit: sorry, I just took away the CRTP element as it's not needed to reproduce)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Wojtek Surowka
  • 20,535
  • 4
  • 44
  • 51
  • 1
    Is this a "yes" or a "no"? – R. Martinho Fernandes Jan 14 '14 at 16:29
  • Sure, that fixes it. But it does not answer the question! – Lightness Races in Orbit Jan 14 '14 at 16:30
  • I would think that it is rather 4.8 bug - I think that without the template argument the code is invalid. Don't have the standard text handy to confirm it though... – Wojtek Surowka Jan 14 '14 at 16:32
  • @WojtekSurowka: The _injected-class-name_ is supposed to be within the scope of the whole type and its derived types. `[C++11: 14.6.1/3]` gives an example, albeit not _quite_ this one. – Lightness Races in Orbit Jan 14 '14 at 16:33
  • I'd vote for 4.8 bug (don't have the standard handy either), what would `Base` refer to in the case of `struct Derived : Base, Base`? – Erbureth Jan 14 '14 at 16:35
  • @Erbureth it's not a 4.8 bug. In that case it's an ambiguity. You could even derive from `std::vector` if you wanted and use `vector` as a name. – Simple Jan 14 '14 at 16:36
  • @Erbureth copies of draft standard can be found [here](http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents). – Shafik Yaghmour Jan 14 '14 at 16:37
  • 1
    @Erbureth: `[C++11: 14.6.1/4]:` _A lookup that finds an injected-class-name (10.2) can result in an ambiguity in certain cases (for example, if it is found in more than one base class). If all of the injected-class-names that are found refer to specializations of the same class template, and if the name is used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous._ – Lightness Races in Orbit Jan 14 '14 at 16:38
  • @Erbureth: In fact, the example in this paragraph is _precisely_ the example you give! And it says that it should be valid as long as there's no ambiguity. That proves that it's a GCC 4.4.1 bug as far as I'm concerned. – Lightness Races in Orbit Jan 14 '14 at 16:39
  • @LightnessRacesinOrbit That decides it then. – Erbureth Jan 14 '14 at 16:39
  • @Erbureth: Thanks for your prodding. :) I didn't spot that example before you spoke up. – Lightness Races in Orbit Jan 14 '14 at 16:43
  • The example is not the same, since Derived is a template in the standard. The whole discussion in 14.6.1 (in my draft it is 14.7.1) is about class templates. In the code above struct Derived is not a template, so 14.6.1 is not relevant. Can anyone point to a text in the standard which explains 4.8 behaviour? – Wojtek Surowka Jan 14 '14 at 16:48
  • @WojtekSurowka: It doesn't really work that way. There's no wording to state that this factor matters. The entirety of 14.6.1 makes my code legal and I'm sure of it now! – Lightness Races in Orbit Jan 14 '14 at 16:50
  • The standard says "The injected-class-name of a class template or class template specialization can be used either with or without a template-argument-list wherever it is in scope." In your case Derived is not a class template or class template specialization, so it is really not relevant. – Wojtek Surowka Jan 14 '14 at 16:52
  • @WojtekSurowka: The _injected-class-name_ in this example is that of `Base`, which is absolutely a class template. – Lightness Races in Orbit Jan 15 '14 at 02:32