C++ Невозможно вызвать метод базового класса из производного класса

это мой первый вопрос, я надеюсь, что я делаю все правильно.

Я пытаюсь получить класс из кортежа повышения. Кортежи Boost предоставляют шаблонный метод get() для доступа к отдельным полям. Интересно, что я не могу использовать метод из производного класса.

Следующий код показывает проблему:

#include <iostream>
#include <boost/tuple/tuple.hpp>
using namespace std;

template<typename A>
class Derived : public boost::tuple<A>
{
public:
    Derived() : boost::tuple<A>() {}

    A& getVal0()
    {
        return get<0>();
        // does not compile:
        //error: 'get' was not declared in this scope

        return boost::tuple<A>::get<0>();
        // does not compile
        //error: expected primary-expression before ')' token

        return boost::tuples::get<0>(*this);
        //works
    }
};  

int main() {
    Derived<int> a;

    a.get<0>() = 5;

    cout << a.get<0>() << endl; 
    cout << a.getVal0() << endl; 
    return 0;
}

Интересно, почему я могу получить доступ к методу get<0>() из основной функции?

a.get<0>() = 5;

но не из метода A& getVal0():

error: 'get' was not declared in this scope

Вторая строка возврата была моей попыткой ограничить вызов метода базовым классом:

return boost::tuple<A>::get<0>();

И это генерирует другую ошибку

error: expected primary-expression before ')' token

Вызов внешней функции `boost::tuples::get‹0>(*this) работает. И этот обходной путь меня устраивает. Но мне все еще интересно, почему я не могу использовать метод кортежа на данный момент.

В документации по ускорению есть уведомление для Visual C++.

Примечание! Функции получения члена не поддерживаются компилятором MS Visual C++. Кроме того, у компилятора возникают проблемы с поиском функций get, не являющихся членами, без явного квалификатора пространства имен. Следовательно, все вызовы get должны быть квалифицированы как: tuples::get(a_tuple) при написании кода, который должен компилироваться с помощью MSVC++ 6.0.

Но я использую GCC 4.5.2 и 4.8.1.

заранее спасибо


person Evil Azrael    schedule 24.11.2013    source источник
comment
+1 Я должен сказать следующее: помимо темы, ваш вопрос следует рассматривать в качестве примера для любого нового пользователя, который публикует сообщения на этом сайте. У вас есть все необходимое для хорошего вопроса, включая (1) проблему, которая, по вашему мнению, у вас есть, (2) пример кода, демонстрирующий эту проблему, (3) попытки решения проблемы, (4) каждый и каждый результат этих попыток, (5) инструменты, которые вы используете, включая информацию о версии, и (6) исследование того, что, по вашему мнению, может быть корневой проблемой. Для поста в целом это круто; для первого поста он просто выдающийся и редко встречается с такой подачей.   -  person WhozCraig    schedule 25.11.2013
comment
WhozCraig очень приятно что можно дать новичку столько хороших слов и положительных советов   -  person 4pie0    schedule 25.11.2013
comment
@piotruś Не сложно, когда публикуется такой вопрос. Я абсолютно серьезно отношусь к тому, что это образцово. Я просто надеюсь, что ОП знает, как пометить решение, потому что я уверен, что оно есть у Дитмара. =П   -  person WhozCraig    schedule 25.11.2013
comment
@WhozCraig. Кажется, я знаю, как пометить решение как принятое. Или, по крайней мере, я должен сделать.   -  person Evil Azrael    schedule 25.11.2013


Ответы (1)


Предполагая, что в базовом классе есть шаблон функции-члена get<I>(), вы, вероятно, захотите использовать

this->template get<0>()

Часть this необходима, чтобы сделать его зависимым поиском (вы также можете использовать правильную квалификацию класса, но это немного неудобно и не нужно, если вы не скрываете имя базового класса). Часть template необходима, чтобы сообщить компилятору, что зависимое имя (get) является шаблоном.

Основная причина, по которой необходимы this (или какая-либо другая квалификация) и template, — это двухэтапная модель компиляции для шаблонов:

  • Любое имя, которое не зависит непосредственно от аргумента шаблона в той или иной форме, просматривается только на этапе I, т. е. в контексте определения шаблона. Поскольку аргумент шаблона неизвестен и, следовательно, неизвестна точная структура базового класса (он может быть специализированным), любое имя в базовом классе игнорируется. Использование любой квалификации, заставляющей имя зависеть от аргумента шаблона, например, использование this->, переводит поиск в фазу II, т. е. когда создается экземпляр шаблона.
  • Как только имя становится зависимым, возникает неоднозначность, если выражение включает символ <, когда шаблон анализируется на этапе I, т. е. когда аргументы шаблона еще не известны: < может быть началом явного аргумента шаблона. для вызова функции-члена или это может быть оператор "меньше". Поскольку явное упоминание аргументов шаблона встречается редко (ну, по крайней мере, это было редко, когда создавались эти правила), по умолчанию предполагается, что это оператор «меньше». Чтобы указать, что имя на самом деле является шаблоном функции-члена с явно заданным аргументом шаблона, ему должно предшествовать ключевое слово template (очень похоже на типы, которым требуется typename).
person Dietmar Kühl    schedule 24.11.2013