Выведите (шаблонный) тип возврата оператора + и других операторов - PullRequest
1 голос
/ 09 февраля 2020

Я реализую двумерный вектор, который может принимать любой арифметический тип c для своих координат. Я хочу реализовать оператор operator+, который выводит его тип возвращаемого значения из контекста таким же образом, что-то вроде unsigned x = 2l + 3.1; знает, что результат + должен быть unsigned, потому что он назначен unsigned.

то, что у меня есть, вдохновлено шаблонами, выводящими тип T из возвращаемого типа :

#include <array>
#include <type_traits>

template<typename T,
         typename = std::enable_if_t<std::is_arithmetic_v<T>, T>>
class Vec2
{
    std::array<T, 2> _data;

public:
    // Constructors
    Vec2(T x, T y): _data{x, y} {}

    // Operators
    template<typename TB, // second operand's coordinates type
             typename TR> // result's coordinates type
    Vec2<TR> operator+(const Vec2<TB> v) const
    {
        return Vec2<TR>(_data[0] + v._data[0],
                        _data[1] + v._data[1]);
    }
};

int main(void)
{
    Vec2 vi{0, 2};
    Vec2 vf{1.4, 2.2};

    Vec2<int> res = vi + vf;
}

И я получаю сообщение об ошибке, в котором говорится, что не удалось вывести тип, используемый для возвращаемое значение:

$ g++ -Wall -Wextra -std=c++17 poc.cc
poc.cc: In function ‘int main()’:
poc.cc:29:24: error: no match for ‘operator+’ (operand types are ‘Vec2<int, int>’ and ‘Vec2<double, double>’)
   29 |     Vec2<int> res = vi + vf;
      |                     ~~ ^ ~~
      |                     |    |
      |                     |    Vec2<double,double>
      |                     Vec2<int,int>
poc.cc:17:14: note: candidate: ‘template<class TB, class TR> Vec2<TR> Vec2<T, <template-parameter-1-2> >::operator+(Vec2<TB>) const [with TB = TB; TR = TR; T = int; <template-parameter-1-2> = int]’
   17 |     Vec2<TR> operator+(const Vec2<TB> v) const
      |              ^~~~~~~~
poc.cc:17:14: note:   template argument deduction/substitution failed:
poc.cc:29:26: note:   couldn’t deduce template parameter ‘TR’
   29 |     Vec2<int> res = vi + vf;
      |                          ^~
poc.cc:29:15: warning: unused variable ‘res’ [-Wunused-variable]
   29 |     Vec2<int> res = vi + vf;
      |               ^~~

1 Ответ

1 голос
/ 09 февраля 2020

В C ++ перегрузка оператора + не позволяет определить, какому результату он будет присвоен. C ++ просто не работает таким образом.

Во многих случаях можно придумать альтернативную альтернативу немного другим способом. Начните с того, что оператор + определит, каким должен быть оптимальный тип возврата:

template<typename TB> // result's coordinates type
auto operator+(const Vec2<TB> v) const
{
    typedef decltype( static_cast<T>(0) + static_cast<TB>(0) ) ret_t;

    return Vec2<ret_t>(_data[0] + v._data[0],
                    _data[1] + v._data[1]);
}

Вы гарантируете, что оба типа T и TB являются арифметическими c, так что это Простейший способ выяснить это через decltype.

Итак, добавление Vec2 из int s к Vec2 из double s должно привести к Vec2<double>. Но что, если это будет присвоено Vec2<int>? Ну, вам просто нужен оператор преобразования ...

template<typename TB>
operator Vec2<TB>() const
{
    return Vec2<TB>(_data[0], _data[1]);
}

... и надежда на лучшее.

...