2012-02-20 3 views
4

У меня есть класс Vector, который представляет собой 2D-вектор. Предусматривается использование любого численного типа для компонентов x и y. В качестве примера, один из арифметических операторов я перегрузкой * для умножения вектора с скаляром:C++ арифметический оператор перегрузки-автоматическое расширение?

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>, а Vector<double> * short => Vector<double>.

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

ответ

3

Существует два решения. В 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.

+2

Удивительно, хотелось бы, чтобы я мог возвыситься не один раз. Я все время вижу хорошие приложения синтаксиса типа '->' return type. –

+2

Отмечая, конечно, что в C++ 11 ваш возвращаемый тип _shouldn't_ будет const, поскольку он препятствует семантике перемещения. – ildjarn

+0

Поддерживает ли это clang ++ 3.0? – mk12

5

Вы можете использовать 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 чувствует себя немного более гигиеничны, так как он не требует, чтобы предоставить реальный экземпляр вашего типа (и, таким образом, он применим даже в ситуациях, когда это невозможно).

+1

Я бы не видел common_type раньше! Это довольно удобно. – Flexo

+0

'declval' также выглядит удобно, +1 –

+0

Просто, кстати, я говорил о своем собственном математическом классе Vector, а не std :: vector, но это все равно отличный ответ. К сожалению, я получаю сообщение об ошибке, когда '# include'ing' ', поэтому я думаю, что это не сработает для меня. – mk12

Смежные вопросы