Преобразование типов для шаблонов

У меня есть шаблон класса-оболочки и хочу иметь неявное преобразование в обернутый тип, чтобы использовать существующие функции библиотеки:

#include <complex>
****** f(****** x) { return 1.; }
template <typename t="">
std::complex<t> f(std::complex<t> x) { return std::complex<t>(); }
template <typename t="">
class A {
 T _x;
public:
 A(const T& x) : _x(x) {}
 operator T() { return _x; }
};
int main() {
 A<******> da(1.);
 A<std::complex<******>> ca({1.,1.});
 f(da); // OK 
 f(ca); // error 
 return 1;
}
</std::complex<******></******></typename></t></t></t></typename></complex>

f(std::complex<t>)</t> не используется для f(ca), потому что неявное преобразование не учитывается при выводе аргумента шаблона (см. сгенерированную ошибку msg. здесь).

В реальном коде f(...) заменяется библиотечными функциями, например. из заголовка , поэтому его нельзя изменить.

Если я наследую A от T (как было предложено сообщением об ошибке), то f(ca) компилируется. Но тогда A не определяется для встроенных типов (вы не можете наследовать их). Кроме того, это даст все функциональные возможности complex до A<complex<******>></complex<******>, которые я хочу избежать.

Есть ли обходной путь для этого?

1 ответ

Чтобы решить проблему "не работает для встроенных типов", вы можете использовать специализированную специализацию. Версия std::complex<> использует наследование.

template <typename t="">
class A {
 T _x;
public:
 A(const T& x) : _x(x) {}
 operator const T &() const { return _x; }
 operator T &() { return _x; }
};
template <typename d="">
class A<std::complex<d>> : public std::complex<d> {
 typedef std::complex<d> T;
public:
 A(const T& x) : T(x) {}
};
</d></d></std::complex<d></typename></typename>

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

template <typename t="">
class A {
 T _x;
 friend A f(A x) { return f(x._x); }
public:
 A(const T& x) : _x(x) {}
 operator const T &() const { return _x; }
 operator T &() { return _x; }
};
</typename>

licensed under cc by-sa 3.0 with attribution.