views:

289

answers:

5

When a template publicly inherits from another template, aren't the base public methods supposed to be accessible?

template <int a>
class Test {
public:
    Test() {}
    int MyMethod1() { return a; }
};

template <int b>
class Another : public Test<b>
{
public:
    Another() {}
    void MyMethod2() {
        MyMethod1();
    }
};

int main()
{
    Another<5> a;
    a.MyMethod1();
    a.MyMethod2();
}

Well, GCC craps out on this... I must be missing something totally obvious (brain melt). Help?

A: 

I think you are just missing a public: at the top of the Another definition. For questions like this it is usually helpful to post the error messages that you are getting.

Dolphin
+2  A: 

main needs a return type.

class Another needs a terminating semi-colon.

class Another needs its members to be public.

Also, methods aren't generally considered invisible; the methods were inaccessible without the public access keyword.

sean e
It's fine to omit a return statement in main() according to the c++ standard, in which case 0 is returned.
TC
Funny - I was thinking of the declaration, as in:void main()....
sean e
IOW - I meant the type was missing from the decl, rather than a return value in the body of main.
sean e
+1  A: 

I cleaned up your code to this:

template <int a>
class Test {
public:
    Test() {}
    int MyMethod1() { return a; }
};

template <int b>
class Another : public Test<b>
{
public:
    Another() {}
    void MyMethod2() {
        MyMethod1();
    }
};


int main()
{
    Another<5> a;
    a.MyMethod1();
    a.MyMethod2();
}

And compiled with -fpermissive with no problems (you can probably resolve this issue).

John Ledbetter
This still has an error (it shouldn't compile in a standard conformant compiler). See my post below.
ltcmelo
MSVC will build this as long as Disable Language Extensions is off (the default).
Dolphin
That's because VC doesn't to proper two-phase lookup. Symbols are, basically, only looked up when the template is instantiated. (I think it does a little bit more, but just barely. It's amazing what kind of stupid mistakes go unnoticed without two-phase lookup until someone instantiates the template. If you wrote the template, that can be quite embarrassing.)
sbi
+12  A: 

This is part of the rules concerning dependent names. Method1 is not a dependent name in the scope of Method2. So the compiler doesn't look it up in dependent base classes.

There two ways to fix that: Using this or specifying the base type. More details on this very recent post or at the C++ FAQ. Also notice that you missed the public keyword and a semi-colon. Here's a fixed version of your code.


template <int a>
class Test {
public:
    Test() {}
    int MyMethod1() { return a; }
};

template <int b>
class Another : public Test<b>
{
public:
    Another() {}
    void MyMethod2() {
        Test<b>::MyMethod1();
    }
};

int main()
{
    Another<5> a;
    a.MyMethod1();
    a.MyMethod2();
}

ltcmelo
+1 for the links.
wheaties
Yep, that's the correct answer. (Note that, TTBOMK, `this->MyMethod1()` should also work.)
sbi
If you think it's insane that this is necessary, you are not alone. Still, it *is* a sad fact of life.
Steve314
+1. Also worth reading is the C++ Template FAQ: http://womble.decadentplace.org.uk/c++/template-faq.html very nice!
Johannes Schaub - litb
That's a nice one, litb. I didn't know Ben's site.
sbi
+5  A: 

You should fully qualify MyMethod1. C++ Standard clearly states this in 14.6.2/3:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

So, you should write:

void MyMethod2() {
    Test<b>::MyMethod1();
}
Kirill V. Lyadvinsky