Перегрузка арифметического оператора C ++ - автоматическое расширение? - PullRequest
4 голосов
/ 21 февраля 2012

У меня есть класс Vector, который представляет двумерный вектор.Он позволяет использовать любой числовой тип для компонентов x и y .Например, один из арифметических операторов, которые я перегружаю, - это * для умножения вектора на скаляр:

template <typename T, typename U>
inline const Vector<T> operator*(const Vector<T>& vector, U scalar) {
    return Vector<T>(vector.x * scalar, vector.y * scalar);
}

(у меня также есть функция с параметрами в обратном порядке, чтобыscalar * Vector в дополнение к Vector * scalar).

Как видите, я использую <T, U> вместо простого <T>, так что скаляр не должен быть того же типа, что иВекторКогда я не сделал это, на удивление Vector<double> * int не скомпилировался (я думал, что int автоматически расширится).

В любом случае, я просто не хочу возвращатьсяVector<T>.Я хочу имитировать встроенные типы и возвращать их в зависимости от того, какая точность выше, T или U.Так, например, Vector<int> * double => Vector<double> while Vector<double> * short => Vector<double>.

Возможно ли это?

Ответы [ 2 ]

5 голосов
/ 21 февраля 2012

Вы можете использовать common_type или decltype, чтобы приготовить что-то, что даст вам результирующий тип; а затем вы должны создать фактический вектор:

template <typename A, typename B>
std::vector<typename std::common_type<A, B>::type>
operator*(std::vector<A> const & v, B const & x)
{
    std::vector<typename std::common_type<A, B>::type> res;
    res.reserve(v.size());
    for (A a : v) res.push_back(a * x);
    return res;
}

Используя decltype, вы можете получить тип результата через:

decltype(std::declval<A>() * std::declval<B>())

Для std::common_type и std::declval необходимо #include <type_traits>.

С типами отложенного возврата (auto и ->) вы можете использовать decltype непосредственно для аргументов функции, но использование std::declval кажется немного более гигиеничным, поскольку не требует от вас предоставления фактического экземпляр вашего типа (и, следовательно, он применим даже в ситуациях, когда это невозможно).

3 голосов
/ 21 февраля 2012

Есть два решения для этого.В Pre C ++ 11 вы можете написать шаблон, например:

template <typename T, typename U>
struct WhatWillItBe {
  typedef T result_t;
};

template <typename T>
struct WhatWillItBe<T, double> {
  typedef double result_t;
};

// ... lots more

и т. Д.и напишите много специализаций, затем вы можете использовать это для поиска типа возвращаемого значения, например:

template <typename T, typename U>
inline const Vector<typename WhatWillItBe<T,U>::result_t> operator*(const Vector<T>& vector, U scalar) {
    return Vector<typename WhatWillItBe<T,U>::result_t>(vector.x * scalar, vector.y * scalar);
}

В качестве альтернативы C ++ 11 делает это простым, вы можетенапишите auto для типа возвращаемого значения и используйте ->, чтобы указать тип возвращаемого значения после остальной части функции:

template <typename T, typename U>
inline auto operator*(const Vector<T>& vector, U scalar) -> Vector<decltype(vector.x*scalar)> {
    return Vector<decltype(vector.x*scalar)>(vector.x * scalar, vector.y * scalar);
}

, который позволяет использовать decltype для возвращаемого типа функции,установив его в зависимости от того, что произойдет для продвижения, естественно, с помощью vector.x * scalar.

...