32bit_me (32bit_me) wrote,
32bit_me
32bit_me

Category:

Шаблоны, параметры, два креста

Ох нехило быть духовным,
в голове одни кресты

(с) БГ



Рассмотрим такой код:

  template <typename T> struct Base {
    public:
    int foo()
    {
        return 42;
    }
  };
 
  template <typename T> struct Derived : public Base<T> {
    int get_i() { return foo(); }
  };


Есть ли в нём что-то подозрительное?
Попробуем инстанциировать шаблон Derived:

Derived<int> a;


И отхватываем непонятную ошибку:

error: there are no arguments to ‘foo’ that depend on a template parameter, so a declaration of ‘foo’ must be available [-fpermissive]
     int get_i() { return foo(); }
 


Что же произошло?

Подробное объяснение вы можете прочитать по ссылке в конце, а сейчас я попробую объяснить своими словами. Современные компиляторы используют для разбора шаблонов двухэтапную технику (two-stage name lookup), разделяя все имена в шаблоне на зависимые от параметров и на независимые. Независимые компилятор рассчитывает найти сразу, а зависимые разрешаются только при инстанцировании, когда будут известны значения параметров. В этом примере вызов foo() в теле шаблона Derived компилятор считает независимым от параметра, хотя на самом деле функция foo() объявлена внутри шаблона Base, который сам по себе зависим от параметра Т. Если компилятор не находит никакой независимой функции foo(), он сообщает об ошибке.

Как же быть? Ответ простой: нужно сделать вызов foo() зависимым от параметра, чтобы компилятор обработал его только при инстанцировании. Это можно сделать двумя способами:

// 1st solution
int get_i() { return this->foo(); }
// 2nd solution
int get_i() { return Base<T>::foo(); }


В первом случае мы указываем, что функция вызывается через this, который, очевидно, зависит от параметра, во втором случае - явно через зависимый от параметра T шаблон Base.

Рассмотрим ещё один пример:

  template <typename T> struct Base {
    int i;
  };
 
  template <typename T> struct Derived : public Base<T> {
    int get_i() { return i; }
  };


Здесь мы получаем другое сообщение об ошибке:

error: ‘i’ was not declared in this scope
 


но его причина заключается в том же.

И снова мы имеем два способа:

// 1st solution
int get_i() { return this->i; }
// 2nd solution
int get_i() { return Base<T>::i; }


Ссылка:
11.9. Common Misunderstandings with GNU C++: https://www.linuxtopia.org/online_books/programming_tool_guides/linux_using_gnu_compiler_collection/c---misunderstandings.html
Tags: c++, программирование
Subscribe

  • С днём космонавтики!

  • Прекрасное под катом

    Людям со слабой психикой под кат не заглядывать! Описание: Книга даёт ответы на главные вопросы науки и человечества, описывает неизвестное…

  • Вселенная-25

    Практически каждый раз, когда начинаются разглагольствования об "обществе потребления", всплывает так называемый "эксперимент Вселенная 25". Если…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 10 comments

  • С днём космонавтики!

  • Прекрасное под катом

    Людям со слабой психикой под кат не заглядывать! Описание: Книга даёт ответы на главные вопросы науки и человечества, описывает неизвестное…

  • Вселенная-25

    Практически каждый раз, когда начинаются разглагольствования об "обществе потребления", всплывает так называемый "эксперимент Вселенная 25". Если…