Оператор + для подтипа шаблонного класса - PullRequest
1 голос
/ 06 мая 2010

У меня есть шаблонный класс, который определяет подтип. Я пытаюсь определить двоичный файл operator+ как функцию шаблона, но компилятор не может разрешить версию шаблона operator+.

#include <iostream>
template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  struct subtype { subtype(other_type v) : val(v) {} other_type val; } cs;
};

template<typename other_type>
typename c<other_type>::subtype operator+(const typename c<other_type>::subtype& left,
                      const typename c<other_type>::subtype& right)
{ return typename c<other_type>::subtype(left.val + right.val); }

// This one works
// c<int>::subtype operator+(const c<int>::subtype& left,
//          const c<int>::subtype& right)
// { return c<int>::subtype(left.val + right.val); }

int main()
{
  c<int> c1 = 1;
  c<int> c2 = 2;
  c<int>::subtype cs3 = c1.cs + c2.cs;
  std::cerr << cs3.val << std::endl;
}

Я думаю, причина в том, что компилятор (g ++ 4.3) не может угадать тип шаблона, поэтому он ищет operator+<int> вместо operator+.

В чем причина? Какое элегантное решение вы можете предложить?

1 Ответ

4 голосов
/ 06 мая 2010

Ваше подозрение верно. Компилятор не знает, что такое other_type. Это не может быть выведено из аргументов. Такие формы часто слишком свободны для предоставления необходимой информации. Рассмотрим

template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  typedef int subtype;
};

Если вы передадите int, то любой из c<T> будет соответствовать требованиям, поскольку все они имеют тип int. В конкретном случае вложенных классов это может быть возможно, но даже тогда это не уникально. Представьте, что в c<float> вы можете поставить typedef c<int> subtype;, тогда и c<float>::subtype, и c<int>::subtype будут соответствовать требованиям.

В предстандартное время существовал список проблем с шаблонами, которые, в частности, Джон Спайсер прошел и изобрел разумные решения. Это была одна из таких проблем, и было установлено, что это не стоит проблем. Вы всегда должны явно указать аргумент - он никогда не выводится.

Вы можете изменить свой код на этот

template<typename other_type> 
struct subtype { 
  subtype(other_type v) : val(v) {}
  other_type val; 
};

template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  subtype<other_type> cs;
};

template<typename other_type>
subtype<other_type> operator+(const subtype<other_type>& left,
                      const subtype<other_type>& right)
{ return subtype<other_type>(left.val + right.val); }

Или к этому

template<typename other_type> 
struct c {
  c(other_type v) : cs(v) {}
  struct subtype { 
   subtype(other_type v) : val(v) {} other_type val; 

    /* note: don't forget friend! */
    friend subtype operator+(const subtype& left,
                      const subtype& right)
    { return subtype(left.val + right.val); }
  } cs;
};
...