Обработайте друга по шаблону функция шаблонного класса

По моему скромному мнению, это действительно не имеет значения с короткими именами таблиц, которые имеют смысл, я при случае работал над базами данных, где имя таблицы могло быть чем-то как VWRECOFLY или некоторая другая случайная строка (продиктованный политикой компании), который действительно представляет пользователей, так в этом случае я нахожу, что псевдонимы действительно помогают сделать FAR кода более читаемым. (users.username делает намного больше с тех пор тогда VWRECOFLY.username)

9
задан Community 23 May 2017 в 12:07
поделиться

1 ответ

... если я изменю прямое объявление оператора << так, чтобы оно не соответствовало

Другую функцию следует рассматривать как особый вид декларации. По сути, компилятор делает достаточно для синтаксического анализа объявления, однако семантическая проверка не будет выполняться, если вы действительно не специализируете класс.

После внесения предложенного вами изменения, если вы затем создадите экземпляр test , вы получите ошибку о том, что объявления не совпадают:

template class test<int>;

... Однако ... удаление прямого объявления вызывает проблему

Компилятор пытается проанализировать объявление, чтобы сохраните его до тех пор, пока шаблон класса не станет специализированным. Во время синтаксического анализа компилятор достигает < в объявлении:

friend std::ostream& operator<<  <

Единственный способ, которым оператор << может сопровождаться <, - это если он шаблон, поэтому выполняется поиск, чтобы убедиться, что это шаблон. Если шаблон функции найден, то < считается началом аргументов шаблона.

Когда вы удаляете предварительное объявление, шаблон не обнаруживается и оператор << считается объектом. (Вот почему, когда вы добавляете с использованием пространства имен std , код продолжает компилироваться, поскольку должны быть объявления шаблонов для operator << ).

... когда я удаляю предварительные объявления и используйте альтернативное объявление друга в приведенном выше коде. Обратите внимание, что параметр шаблона U не появляется в следующей сигнатуре ...

Не требуется, чтобы все параметры шаблона использовались в аргументах шаблона функции. Альтернативное объявление предназначено для нового шаблона функции, который можно будет вызывать только в том случае, если он объявлен в пространстве имен и указывает явные аргументы шаблона.

Простым примером этого может быть:

class A {};
template <typename T> A & operator<<(A &, int);

void foo () {
  A a;
  operator<< <int> (a, 10);
}

... это действительно правильный код? ..

Здесь есть две части. Во-первых, альтернативная функция друга не ссылается на объявление позже в области видимости:

template <typename T>
class test {
  template <typename U> 
  friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
  };

template <typename T> 
std::ostream& operator<<(std::ostream &out, const test<T> &t);  // NOT FRIEND!

Функция друга фактически будет объявлена ​​в пространстве имен для каждой специализации:

template <typename U> 
std::ostream& operator<<(std::ostream &out, const test<int> &t);
template <typename U> 
std::ostream& operator<<(std::ostream &out, const test<char> &t);
template <typename U>
std::ostream& operator<<(std::ostream &out, const test<float> &t);

Каждая специализация оператора << будет иметь доступ к конкретной специализации в соответствии с типом ее параметра test . Таким образом, по сути, доступ ограничен по вашему запросу. Однако, как я упоминал ранее, эти функции в основном непригодны для использования в качестве операторов, поскольку вы должны использовать синтаксис вызова функций:

int main ()
{
  test<int> t;
  operator<< <int> (std << cout, t);
  operator<< <float> (std << cout, t);
  operator<< <char> (std << cout, t);
}

В соответствии с ответами на предыдущий вопрос вы либо используете предварительное объявление, как предложено в litb , или вы можете определить встроенную функцию друга в соответствии с ответом Dr_Asik (что, вероятно, было бы тем, что я сделал бы).

ОБНОВЛЕНИЕ: 2-й комментарий

... изменение прямого объявления перед классом; один в классе по-прежнему соответствует функции, которую я реализую позже ...

Как я указал выше, компилятор проверяет, является ли operator << шаблоном, когда видит < в объявлении:

friend std::ostream& operator<<  <

Это делается путем поиска имени и проверки, является ли оно шаблоном. Пока у вас есть фиктивное предварительное объявление, это «обманывает» компилятор, заставляя его рассматривать вашего друга как имя шаблона, и поэтому < считается началом списка аргументов шаблона.

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

Вы можете сделать это здесь, потому что (как я сказал ранее),

7
ответ дан 4 December 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: