Изменить тип шаблона С++ T как "long T"?
Есть ли способ удвоить точность, возвращаемую умножением (чтобы избежать переполнения)?
template<class T> class MyClass {
T multiply (T a, T b) { return a * b; }
}
Что-то вроде:
long T multiply (T a, T b) { return a * b; }
Таким образом, если бы были заданы "int", "long" или "double", то из long-long будет длинный int, long long или long long.
Это общий вопрос. Я работаю над этим, используя двойное внутреннее. Но мой вопрос заключается в том, есть ли какой-либо механизм продвижения типа к его "длинному" варианту в С++?
Ответы
Ответ 1
Возможное решение - определить свой собственный характер:
template<typename T>
struct add_long { typedef T type; };
template<>
struct add_long<int> { typedef long int type; };
template<>
struct add_long<double> { typedef long double type; };
template<>
struct add_long<long int> { typedef long long int type; };
// And so on...
Вот как вы могли бы использовать его в своем классе:
template<class T>
class MyClass {
public:
typedef typename add_long<T>::type longT;
longT multiply (longT a, longT b) { return a * b; }
};
И вот небольшой тест:
#include <type_traits>
int main()
{
MyClass<int> m;
auto l = m.multiply(2, 3);
static_assert(std::is_same<decltype(l), long int>::value, "Error!");
}
Ответ 2
@У Энди есть правильный ответ, который работает достаточно хорошо. Но для тех, кто хочет ошибку времени компиляции, если MyClass создается с типом, для которого нет "длинного" значения, я объединил его с замечательным комментарием @SteveJessop, чтобы дать следующее решение:
// --- Machinery to support double-precision 'T' to avoid overflow in method 'multiply' ---
// Note: uncomment typedef if don't want compile-time errors
// when no "long" type exists
// ----
template<typename T>
struct add_long { /*typedef T type;*/ };
template<> struct add_long<int8_t> { typedef int16_t type; };
template<> struct add_long<int16_t> { typedef int32_t type; };
template<> struct add_long<int32_t> { typedef int64_t type; };
template<> struct add_long<uint8_t> { typedef uint16_t type; };
template<> struct add_long<uint16_t> { typedef uint32_t type; };
template<> struct add_long<uint32_t> { typedef uint64_t type; };
template<> struct add_long<float> { typedef double type; };
template<> struct add_long<double> { typedef long double type; };
Пример использования longT:
template<class T> class MyClass
{
// Note: a compiler error on the next line means that
// class T has no double-precision type defined above.
typedef typename add_long<T>::type longT;
public:
longT multiply (T a, T b) { return longT(a) * b; }
}
Пример использования MyClass:
MyClass<float> my;
printf("result = %lf\n", my.multiply(3.4e38, 3.4e38));