У меня есть шаблон класса Foo<T>
.
Я хотел бы реализовать функцию, не являющуюся членом Bar
, которая принимает два Foo
с и возвращает Foo
. Я хочу, чтобы Bar
не был участником, поскольку для вызывающих абонентов будет более естественно написать Bar(f1, f2)
, чем f1.Bar(f2)
. Я также хочу, чтобы Bar
было inline
, потому что вычисления тривиальны и часты.
template <typename T>
inline Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs) {
...
}
Хитрость в том, что Bar
нужен доступ к личным данным Foo
. Я бы предпочел не иметь доступа к частным данным - нет веских оснований предоставлять личные данные пользователям. Поэтому я хотел бы сделать Bar
другом Foo
.
template <typename T>
class Foo {
...
private:
T w, x, y, z;
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
Здесь я сталкиваюсь с неприятностями. Компилятор жалуется:
Встроенный спецификатор нельзя использовать, когда объявление друга ссылается на специализацию шаблона функции.
Это правило наложено стандартом или оно специфично для MSVC ++?
Вот что я пробовал:
Сделать Bar
постоянной публичной функцией-членом, а затем объявить версию, не являющуюся членом, которая просто возвращает lhs.Bar(rhs)
. Это кажется наименее хакерским решением.
Удалите подсказку inline
, зная, что компилятор примет решение о вставке независимо от подсказки. Это тогда противоречит правилу с одним определением? Его все равно нужно будет определить в заголовочном файле, потому что это шаблон функции.
Объявить функцию-член с фиктивным типом шаблона:
template <typename T>
class Foo {
...
private:
T w, x, y, z;
// Note that this declaration doesn't actually use Dummy. It's just there to
// satisfy the compiler.
template <typename Dummy>
friend Foo<T> Bar(const Foo<T> &lhs, const Foo<T> &rhs);
};
Я не совсем уверен, почему это работает, но оно удовлетворяет компилятору.
Есть ли лучшее решение?