я написал шаблонный класс, который должен работать для double и std :: complex. как и должно быть, все мои методы находятся в файле .hpp. все кроме одного. Я должен был специализировать метод, потому что в каком-то месте я должен вычислить квадрат двойного или норма std :: complex. более явно для «двойной специализации» (A):
double a(2.0);
double b(0.0);
b = a*a;
для «комплексной специализации» (Б):
std::complex<double> a(2.0,3.0);
double b(0.0);
b = std::norm(a);
мои вопросы:
Есть ли способ избежать этих специализаций, используя функцию, которая работает как для двойных, так и для сложных? (потому что std :: norm работает только для сложных …)
или единственное решение состоит в том, чтобы преобразовать двойную специализацию (A) в комплекс, а затем использовать только специализацию (B) в качестве общего шаблона (работая как для двойной, так и для сложной)?
Вы можете свести к минимуму расходящийся случай, введя свою собственную функцию в качестве обертки для квадрата / нормы:
template <typename T>
double square_or_norm(T x);
template<>
inline double square_or_norm(double x) { return x * x; }
template <>
inline double square_or_norm(std::complex<double> x) { return norm(x); }
Затем используйте его внутри функции, которая нуждается в этом:
template <typename T>
T computation(T x) {
return some_code_with(x, square_or_norm(x));
}
Вы можете определить две функции шаблона перегрузки (когда дело доходит до шаблонов функций, перегрузка обычно предпочтительнее специализация) называется compute_norm()
один принимает std::complex
и один принимает неограниченные типы. Неограниченный шаблон будет вызывать operator *
в то время как ограниченный шаблон будет вызывать std::norm()
,
#include <complex>
template<typename T>
double compute_norm(T t)
{ return t * t; }
template<typename T>
double compute_norm(std::complex<T> const& t)
{ return std::norm(t); }
Затем ваш общий код, который может работать как с double
и с complex<double>
назвал бы compute_norm()
:
#include <iostream>
template<typename T>
void foo(T&& t)
{
// ...
double n = compute_norm(std::forward<T>(t));
std::cout << n << std::endl;
// ...
}
Например, следующая программа:
int main()
{
double a(2.0);
foo(a);
std::complex<double> c(2.0, 3.0);
foo(c);
}
Будет выводить:
4
13
Вот живой пример.
Если у вас есть соответствующая стандартная библиотека, существует перегрузка std::norm
для типов с плавающей точкой:
26.4.9 Дополнительные перегрузки [cmplx.over] Следующие шаблоны функций должны иметь дополнительные перегрузки:
arg norm
conj proj
imag real
Дополнительные перегрузки должны быть достаточными для обеспечения:
- Если аргумент имеет тип long double, то он фактически приводится к сложному.
- В противном случае, если аргумент имеет тип double или целочисленный тип, он фактически приводится к сложному<
двойной>.- В противном случае, если аргумент имеет тип float, он фактически приводится к комплексу.
Это должно работать (и делает на gcc 4.7.2)
#include <complex>
#include <iostream>
int main()
{
std::complex<double> c {1.5, -2.0};
double d = 2.5;
std::cout << "|c| = " << std::norm(c) << '\n'
<< "|d| = " << std::norm(d) << '\n';
}
Почему бы просто не использовать перегрузку функций?
double myNorm(double);
double myNorm(std::complex<double>);double myNorm(double x) {
return x * x;
}
double myNorm(std::complex<double> x) {
return std::norm(x);
}
Вы можете поместить реализацию в ваш .cpp или (если он встроен) в ваш заголовочный файл.