c++templatesinheritancename-lookuptemplate-inheritance

Accessing base member functions in class derived from template class


I am developing a library at my work and I have designed a complicated inheritance that includes template classes and deriving from them. My problem is that a base template class has virtual overloaded operator that takes 2 arguments and returns some value. In base class this operator is implemented and most of derived classes does not reimplement this operator.

Some other class uses derived classes for some work and make use of their operator member function. Everything works just fine as long as derived class has no other overloaded operator, even with different number of arguments. If one does then the base class operator is not accessible using it as object() because compiler can not find proper member function (complains about argument count missmatch).

It does not matter wether default template arguments for base class was specified or not. Also order of definitions of derived classes does not change which operator cause the problem (it is always SpecificDerived class).

Below I present simplified problem.

[EDIT] Example was simplified

Base Class definition:

template<class ret_t>
class TemplateBase2
{
public:
    virtual ~TemplateBase2()
    {
    }

    virtual ret_t memberFunc(ret_t x)
    {
        return x * 2;
    }
};

User of derived classes definition:

template <class worker, class ret_t>
ret_t gobble(worker w, float f)
{
    return w.memberFunc((ret_t)f);
}

Derived class:

class SpecificDerived2: public TemplateBase2<float>
{
public:
    float memberFunc()
    {
        return 3.14;
    }
};

Main function:

#include <iostream>
#include "TemplateBase2.h"

using namespace std;

int main()
{
    SpecificDerived2 sd2;

    cout << "sd2: " << gobble<SpecificDerived2, float>(sd2, 3.14f) << endl; 
    return 0;
}

Compiler exits with error claiming that there is no matching function for call to 'SpecificDerived2::memberFunc(float)' from gobble function. Problem exists only when either derived or base class has two overloaded functions of the same name, but different arguments.

I am using MinGW32 4.8.1 with c++11 support.


Solution

  • When a class template derives from a base class template, the base members are not visible in the derived class template definition. (This makes sense; until you specialize, there is no class, and so there are no members. Explicit specializations can always change the meaning of any given template class.)

    In other words, the base template member names are dependent names and not looked up in the first phase of template definition lookup.

    There are three ways to get around this. Let's make it concrete with a quick example:

    template <typename T> struct Foo
    {
        int data;
        using type = const T &; 
        void gobble() const;
        template <int N> void befuddle();
    };
    
    template <typename T> struct X : Foo<T> { /* ... */ };
    

    Now in the context of the derived class template definition, you can...

    1. Qualify the name:

      Foo<T>::data = 10;
      typename Foo<T>::type x;
      Foo<T>::gobble();
      Foo<T>::template befuddle<10>();
      
    2. Use this:

      this->data = 10;
      this->gobble();
      this->template befuddle<10>();
      

      (This doesn't work for type names names.)

    3. Use a using declaration:

      using Foo<T>::data;
      using Foo<T>::gobble;
      using type = typename Foo<T>::type;
      
      data = 10;
      gobble();
      

      (This doesn't work for template names.)


    Update: After your edit, the question is entirely different. Templates don't play a role at all here, since the problem doesn't contain templates, only classes. What's happening is the simple fact that member functions in a derived class hide member functions of the same name in base classes, so the presence of SpecificDerived2::memberFunc hides the base member function. The simple solution is to unhide base members of the same name with a using declaration:

    class SpecificDerived2 : public TemplateBase2<float>
    {
    public:
        using TemplateBase2<float>::memberFunc;
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
        float memberFunc()
        {
            return 3.14;
        }
    };