Не могли бы вывести аргумент шаблона? - PullRequest
1 голос
/ 08 августа 2011

У меня есть следующий класс

template<typename hi_t, typename lo_t>
struct int_t
{
hi_t hi;
lo_t lo;

int_t() : lo(0), hi(0) {}
int_t(int value) : lo(value), hi( value<0u? -1: 0 ) {}
int_t(unsigned value) : lo(value), hi( 0 ) {}

int_t& operator+=(const int_t& rhs)
{
    lo_t _lo = lo;

    lo += rhs.lo;
    hi += rhs.hi;
    hi += (int)(lo < _lo);

    return *this;
}

template<typename hi_t, typename lo_t>
inline friend int_t<hi_t, lo_t> operator+(const int_t<hi_t, lo_t>&, const int_t<hi_t, lo_t>&);
};

template<typename hi_t, typename lo_t>
int_t<hi_t, lo_t> operator+(const int_t<hi_t, lo_t>& lhs, const int_t<hi_t, lo_t>& rhs)
{ return int_t<hi_t, lo_t>(lhs) += rhs; }

при выполнении следующего кода

typedef int_t<long long, unsigned long long> int128;

int main()
{
    int128 i = 1024;
    i = i + 20;
}

компилятор выдаст ошибку:

'int_t<hi_t,lo_t> operator +(const int_t<hi_t,lo_t> &,const int_t<hi_t,lo_t> &)' : could not deduce template argument for 'const int_t<hi_t,lo_t> &' from 'int'

когда я помещаю код оператора шаблона в тело класса - с удалением строки шаблона из оператора друга - он работает, но с оператором друга вне класса он не может вывести оператор. я думал, что когда компилятор сгенерирует код для этого оператора шаблона, входные параметры и возвращаемое значение будут иметь тип int128, поэтому у него не должно возникнуть проблем с приведением типа int к этому типу.

UPDATE

если мы определили оператор друга внутри класса следующим образом, работает предыдущий пример

template<typename hi_t, typename lo_t>
struct int_t
{
hi_t hi;
lo_t lo;

int_t() : lo(0), hi(0) {}
int_t(int value) : lo(value), hi( value<0u? -1: 0 ) {}
int_t(unsigned value) : lo(value), hi( 0 ) {}

int_t& operator+=(const int_t& rhs)
{
    lo_t _lo = lo;

    lo += rhs.lo;
    hi += rhs.hi;
    hi += (int)(lo < _lo);

    return *this;
}

friend int_t operator+(const int_t& lhs, const int_t& rhs)
{ return int_t(lhs) += rhs; }

};

проблема возникает при попытке определить оператор шаблона вне класса

Ответы [ 4 ]

4 голосов
/ 08 августа 2011

Код сложнее, чем кажется на первый взгляд.Самая сложная часть - это объявление функции друга.Вы должны взглянуть на этот ответ относительно поддержки функции из шаблона.Краткая рекомендация состоит в том, чтобы удалить шаблонное operator+ и реализовать его как не-шаблонную функцию друга внутри объявления класса:

template<typename hi_t, typename lo_t>
struct int_t
{
// ...
    friend int_t operator+(int_t lhs, const int_t& rhs ) {
        return lhs+=rhs;
    }
};

Что касается конкретной ошибки, то онаможет быть не очень полезным, и это может даже сбить с толку, но вы можете начать с учета того, что шаблон будет учитываться только при перегрузке операторов, если после вывода типа он идеально подходит (т. е. преобразование не требуется).Это означает, что int128_t + int никогда не будет соответствовать шаблонному operator+, имеющему одинаковый тип для левой и правой стороны, , даже если имеет место преобразование.

ПредлагаемыйРешение выше объявляет (и определяет) не шаблонную функцию.Поскольку он определен внутри класса, он будет рассматриваться только с помощью Argument Dependent Lookup и, таким образом, будет применяться только тогда, когда один из операторов равен int_t, если он найден в ADL, то он будет выбран для разрешения перегрузки.с обычными не шаблонными правилами, это означает, что компилятор может использовать любые возможные преобразования как в lhs, так и в rhs (одно из них должно быть экземпляром int_t, если оно было найдено ADL, но оно преобразует другое).

1 голос
/ 08 августа 2011

Включите все предупреждения вашего компилятора.

В ваших объявлениях friend вы используете те же имена параметров шаблона, что и в самом классе шаблона, что не очень хорошо; переименуй их. Вот одно решение: удалите определение оператора вне строки и сделайте встроенное определение следующим:

template<typename H, typename L>
inline friend int_t operator+(const int_t & lhs, const int_t<H, L> & rhs)
{
  return int_t(lhs) += rhs;
}

Теперь, так как ваша RHS - произвольный тип, вы должны указать тип:

i = i + int128(20);

Это потому, что нет способа вывести параметры H,L из целого числа 20, чтобы можно было выполнить соответствующее преобразование в int_t<H,L>(20) (см. Ответ Наваза)!


Чтобы воспользоваться конструктором преобразования из int, вы можете работать только с тем же типом, а не с шаблонным другим типом. Для этого добавьте не шаблонный оператор:

int_t operator+(const int_t & rhs) const { return int_t(*this) += rhs; }

Теперь вы можете сказать i = i + 20;, используя конструктор int_t(int).

Обновление: Как предполагает OP, чтобы разрешить симметричный вызов (i = 50 + i;) и разрешить только операции внутри фиксированного типа, как предлагает Дэвид, мы должны удалить как унарный оператор, так и двоичный оператор шаблонного друга и вместо него просто двоичный друг без шаблонов:

friend int_t operator+(const int_t & lhs, const int_t & rhs) { return int_t(lhs) += rhs; }

Это вопрос выбора дизайна; Я лично предпочел бы окончательный вариант.

0 голосов
/ 08 августа 2011

Вы уверены, что operator+= должен быть шаблоном участника?Обычно вы просто

inline friend int_t operator+(const int_t&, const int_t&) {...}
0 голосов
/ 08 августа 2011

Я не уверен, но, возможно, компилятору снова понадобится аргумент шаблона

...
...
...

template<typename hi_t, typename lo_t>
int_t& operator+=(const int_t& rhs)
{
...
...
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...