Может ли компоновщик различать шаблонные и не шаблонные функции? - PullRequest
0 голосов
/ 03 мая 2019

Я натолкнулся на правило, что функции друга шаблона должны быть объявлены следующим образом:

template<typename T>
class Rational;
template<typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs);

template<typename T>
class Rational {
public:
    friend
    const Rational operator *<> (const Rational& lhs, const Rational& rhs);
};

template<typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs)
{
  return Rational<T>();
}

int main(void)
{
  Rational<int> r;
  r = r * r;
  return 0;
}

, а не просто писать

template<typename T>
class Rational {
public:
    friend
    const Rational operator * (const Rational& lhs, const Rational& rhs);
};

template<typename T>
const Rational<T> operator* (const Rational<T>& lhs, const Rational<T>& rhs)
{
  return Rational<T>();
}

И прочитать объяснение для того, чтобы заявить, что:

Замедление происходит, когда компилятор видит линии друзей вверх в собственном определении класса.В этот момент он еще не знает, что функции друзей сами являются шаблонами;он предполагает, что они не являются шаблонами ...

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

Но в моем понимании r * r должен создать экземпляр

const Rational<int> operator* (const Rational<int>& lhs, const Rational<int>& rhs);

Как это отличается от того, что становится другом Rational<int>?

Может ли компилятор / компоновщик различать функции шаблона и не шаблон?

1 Ответ

1 голос
/ 03 мая 2019

Согласно правилам языка ([temp.fct] / 2):

Функция, не связанная с шаблоном, не связана с шаблоном функции (т.е. она никогда не считается специализацией), даже если она имеет то же имя и тип, что и потенциально генерируемая специализация шаблона функции.

Со вторым фрагментом, когда создается экземпляр Rational<int>, объявление друга в его теле вводит объявление функции non-template :

const Rational<int> operator*(const Rational<int>&, const Rational<int>&);

Определения этой функции не существует в программе, и, собственно говоря, шаблон operator* даже не создается, поскольку он теряет разрешение перегрузки для не-шаблона operator*. Таким образом, с точки зрения компоновщика, operator* вообще нет.

Но даже если шаблон operator* был создан, что заставило компилятор выдать определение

const Rational<int> operator*<int>(const Rational<int>&, const Rational<int>&);

эта функция отличается от не шаблонной operator*, определение которой на самом деле требуется для r * r. Если компоновщик разрешит r * r вызывать специализацию шаблона, это вызовет r * r, чтобы вызвать функцию, отличную от той, которую стандарт должен объявить. (Однако, технически, компоновщик не обязан выдавать сообщение об ошибке, так как это ошибка «не требуется диагностика».)

Поэтому необходимо заранее объявить шаблон operator* и убедиться, что объявление друга ссылается на этот шаблон (или его специализацию).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...