Объявите шаблонную функцию, берущую два объекта класса шаблона friend для (только) этих двух специализаций
У меня есть класс шаблона Test
(с целым числом в качестве аргумента шаблона) и функция шаблона (в данном случае operator*
), которая принимает два объекта класса Test
С возможно различными аргументами шаблона. Функция должна быть дружественной к обоим своим аргументам. Вот минимально рабочий пример:
#include <type_traits>
template <int N>
class Test;
template <int N1, int N2>
Test<N1+N2> operator* (Test<N1>, Test<N2>);
template <int N>
class Test {
double val;
public:
Test (double x) : val{x} {}
template <int N1, int N2>
friend Test<N1+N2> operator* (Test<N1>, Test<N2>);
};
template <int N1, int N2>
Test<N1+N2> operator* (Test<N1> x, Test<N2> y) {
return Test<N1+N2> {x.val*y.val};
}
int main (int argc, char* argv[]) {
Test<1> a{4.}, c{7.9};
Test<2> b{3.5};
a*b;
a*c;
return 0;
}
Это работает, но функция является другом для всех специализаций Test
. Я хочу, чтобы он был другом только с Test<N1>
и Test<N2>
.
Я попытался объявить это так: это:
template <int N>
class Test {
double val;
public:
Test (double x) : val{x} {}
template <int N1, int N2>
friend std::enable_if_t<N1==N||N2==N,Test<N1+N2>> operator* (Test<N1>, Test<N2>);
};
Но встречались ошибки g++ для неоднозначных перегрузок. Я также попытался:
template <int N>
class Test {
double val;
public:
Test (double x) : val{x} {}
template <int N1, int N2, typename = std::enable_if_t<N1==N||N2==N>>
friend Test<N1+N2> operator* (Test<N1>, Test<N2>);
};
Но аргументы шаблона по умолчанию не допускаются для объявлений друзей.
Я предпочитаю решение в C++14, но решения в C++17 также были бы приемлемы.
Обновление: после ответа S. M. Я предлагаю следующее решение для тех, у кого есть подобные проблемы
template <int N>
class Test {
double val;
public:
Test (double x) : val{x} {}
template <int N2>
Test<N+N2> operator* (Test<N2> y) {
return Test<N+N2> {val*y.val};
}
template <int N2>
friend class Test;
};
int main (int argc, char* argv[]) {
Test<1> a{4.}, c{7.9};
Test<2> b{3.5};
a*b;
a*c;
return 0;
}
2 ответа:
Я предлагаю решение ниже. Эта функция больше не является функцией друга.
#include <type_traits> template <int N> class Test { double val; public: Test (double x) : val{x} {} template <int N2> Test<N+N2> mul(const Test<N2> &y) const { return Test<N+N2>{val * y.val}; } template <int N2> friend class Test; }; template <int N1, int N2> Test<N1+N2> operator* (const Test<N1> &x, const Test<N2> &y) { return Test<N1+N2>{x.template mul<N2>(y)}; } int main (int argc, char* argv[]) { Test<1> a{4.}, c{7.9}; Test<2> b{3.5}; a*b; a*c; return 0; }
Как член
operator *
:#include <type_traits> template <int N> class Test { double val; public: Test (double x) : val{x} {} template <int N2> Test<N+N2> operator *(const Test<N2> &y) const { return Test<N+N2>{val * y.val}; } template <int N2> friend class Test; }; int main (int argc, char* argv[]) { Test<1> a{4.}, c{7.9}; Test<2> b{3.5}; a*b; a*c; return 0; }
Нет, ты не можешь этого сделать.
17.5.4 друзья [темп.друг]
Другом класса или шаблона класса может быть шаблон функции или шаблон класса, специализация шаблона функции или шаблона класса, или не-шаблон функции или класса.
Из этих 6 вариантов вам может быть интересен шаблон функции.
Таким образом, вы можете подружиться с оператором тремя способамиtemplate <int N1, int N2> friend Test<N1+N2> operator* (Test<N1>, Test<N2>); #1 template <int N2> friend Test<N + N2> operator* (Test<N>, Test<N2>); #2 template <int N1> friend Test<N1 + N> operator* (Test<N1>, Test<N>); #3
Вариант №1 Вы пробовали, и он не работает, как вы хотелось бы этого. Варианты #2 и #3 также не будут работать по двум причинам: Во-первых, вам нужно будет где-то определить эту перегрузку, во-вторых, если вы определяете такую перегрузку, она не будет работать со вторым параметром (#2) и с первым параметром (#3).