Перегрузка оператора друга в шаблоне C ++ - PullRequest
10 голосов
/ 21 октября 2010

Что не так с моим кодом?

template<int E, int F>
class Float
{
 friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);
};

G ++ просто держит предупреждение:

float.h:7: warning: friend declaration ‘Float<E, F> operator+(const Float<E, F>&, const Float<E, F>&)’ declares a non-template function

float.h:7: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning

Я пытался add <> after the function name here, как указано в предупреждении, но g ++ выдает мне ошибку.

Я скомпилировал код с помощью clang ++, все было нормально, вообще без предупреждения.

Ответы [ 3 ]

31 голосов
/ 21 октября 2010

Это всего лишь предупреждение о сложном аспекте языка.Когда вы объявляете функцию friend, она не является членом класса, в котором находится объявление. Вы можете определить его там для удобства, но на самом деле он принадлежит пространству имен.

Объявление функции-друга, которая являетсяне шаблон, внутри шаблона класса, все еще объявляет не шаблонную функцию в пространстве имен.Он не является ни членом класса, ни самим шаблоном.Тем не менее, генерируется шаблоном класса.

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

Еще одна хитрость в друзьях заключается в том, что объявление внутри class Float {} не объявляет функцию впространство имен.Вы можете найти его только через зависящее от аргумента значение разрешения перегрузки, то есть, указав, что аргумент имеет тип Float (или ссылку, или указатель).Это не проблема для operator+, так как в любом случае она может быть перегружена и никогда не будет вызываться, за исключением пользовательских типов.

Для примера потенциальной проблемы представьте, что у вас естьконструктор преобразования Float::Float( Bignum const& ).Но Bignum не имеет operator+.(Извините, надуманный пример.) Вы хотите положиться на operator+(Float const&, Float const&) для добавления Bignum.Теперь my_bignum + 3 не будет компилироваться, поскольку ни один из операндов не является Float, поэтому он не может найти функцию friend.

Возможно, вам не о чем беспокоиться, если рассматриваемая функция является operator.

Или вы можете изменить friend на шаблон.В этом случае он должен быть определен вне блока class {} и объявлен перед ним, вместо того, чтобы быть объявленным и определенным внутри .

template<int E, int F> // now this is a template!
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);

template<int E, int F>
class Float
{
  // deduce arguments E and F - this names operator+< E, F >.
 friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs);
};
3 голосов
/ 16 июля 2013

Это довольно старая тема, но я думаю, что самый простой способ объявить оператор - это определить его внутри класса Float.

template<int E, int F>
class Float
{
public:
    friend Float operator+ (const Float &lhs, const Float &rhs)
    {
        // Whatever you need to do.
    }
};

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

MSDN: Функции друзей, определенные в объявлениях класса, не рассматриваются в области действия включающего класса;они находятся в области видимости файла.

1 голос
/ 21 октября 2010

Вы должны сделать именно так, как говорится в предупреждениях:

template<int E, int F>
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs);

template<int E, int F>
class Float
{
 friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs);
};

Это объявляет полную специализацию шаблона оператора другом определенного экземпляра шаблона класса. В комментарии к вопросу UncleBens любезно предоставил ссылку на объяснение , почему это так сложно.

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