Доступ к базовым функциям-членам в классе, производном от шаблона

Я занимаюсь разработкой библиотеки на своей работе, и я разработал сложное наследование, которое включает в себя шаблоны классов и производные от них. Моя проблема в том, что базовый шаблонный класс имеет виртуальный перегруженный оператор, который принимает 2 аргумента и возвращает некоторое значение. В базовом классе этот оператор реализован, и большинство производных классов не переопределяет этот оператор.

Некоторые другие классы используют производные классы для некоторой работы и используют их функцию-член оператора. Все работает просто отлично, если в производном классе нет другого перегруженного оператора, даже с разным количеством аргументов. Если это так, оператор базового класса недоступен, используя его как object() потому что компилятор не может найти правильную функцию-член (жалуется на несоответствие количества аргументов).

Неважно, были ли заданы стандартные аргументы шаблона для базового класса или нет. Также порядок определений производных классов не меняет, какой оператор вызывает проблему (это всегда SpecificDerived учебный класс).

Ниже я представлю упрощенную проблему.

[РЕДАКТИРОВАТЬ] Пример был упрощен

Определение базового класса:

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

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

Пользователь определения производных классов:

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

Производный класс:

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

Основная функция:

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

using namespace std;

int main()
{
    SpecificDerived2 sd2;

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

Компилятор завершает работу с ошибкой, утверждая, что есть no matching function for call to 'SpecificDerived2::memberFunc(float)' от gobble функция. Проблема существует только тогда, когда у производного или базового класса есть две перегруженные функции с одинаковыми именами, но с разными аргументами.

Я использую MinGW32 4.8.1 с поддержкой C++11.

1 ответ

Решение

Когда шаблон класса является производным от шаблона базового класса, базовые члены не отображаются в определении шаблона производного класса. (Это имеет смысл; до тех пор, пока вы не будете специализироваться, класса нет, и поэтому нет членов. Явные специализации всегда могут изменить значение любого данного класса шаблона.)

Другими словами, имена членов базового шаблона являются зависимыми именами и не ищутся на первом этапе поиска определения шаблона.

Есть три способа обойти это. Давайте сделаем это на конкретном примере:

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> { /* ... */ };

Теперь в контексте определения шаблона производного класса вы можете...

  1. Уточните имя:

    Foo<T>::data = 10;
    typename Foo<T>::type x;
    Foo<T>::gobble();
    Foo<T>::template befuddle<10>();
    
  2. использование this:

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

    (Это не работает для имен имен типов.)

  3. Использовать using объявление:

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

    (Это не работает для имен шаблонов.)


Обновление: после редактирования вопрос совершенно другой. Шаблоны здесь не играют никакой роли, так как проблема не в шаблонах, а только в классах. Происходит тот простой факт, что функции-члены в производном классе скрывают функции-члены с одинаковыми именами в базовых классах, поэтому наличие SpecificDerived2::memberFunc скрывает базовую функцию-член Простое решение состоит в том, чтобы отобразить базовые элементы с тем же именем с помощью using объявление:

class SpecificDerived2 : public TemplateBase2<float>
{
public:
    using TemplateBase2<float>::memberFunc;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    float memberFunc()
    {
        return 3.14;
    }
};
Другие вопросы по тегам