Typedef и оператор ostream для std :: vector - PullRequest
4 голосов
/ 12 февраля 2011

Я создал класс Chromosome, который в итоге стал просто обёрткой для вектора с оператором ostream, поэтому я решил вместо этого ввести defde vector Однако у меня возникли проблемы с шаблонным оператором ostream ... Это лучший способ? (Я видел несколько подходов и не смог заставить их работать)

template<typename G>
class Chromosome {
 public:
  typedef typename std::vector<G> type;
  typedef typename std::pair<type *,type *> ptr_pair;
};

template<typename G> //line 19 below:
std::ostream& operator<<(std::ostream& os, const Chromosome<G>::type& chromosome) {
  for(auto iter = chromosome.begin(); iter != chromosome.end(); ++iter)
    std::cout << *iter;
  return os;
}

На данный момент я получаю ошибку:

chromosome.h:19: error: expected unqualified-id before ‘&’ token
chromosome.h:19: error: expected ‘)’ before ‘&’ token
chromosome.h:19: error: expected initializer before ‘&’ token

Приветствие.

Ответы [ 2 ]

6 голосов
/ 12 февраля 2011

К сожалению, нет чистого способа сделать это, потому что компилятор не может определить тип G из объявления функции

template<typename G>
std::ostream& operator<<(std::ostream& os, const typename Chromosome<G>::type& chromosome);

Причина в том, что если бы вы специализировали Chromosome для разных типов, вы могли бы оказаться в ситуации, когда компилятор не мог бы однозначно вывести G. Например:

template <typename G> class Chromosome {
public:
    typedef std::vector<G> type; // No typename needed here, BTW
};

template <> class Chromosome<int> {
public:
    typedef std::vector<double> type;
};

Теперь, что случилось бы, если бы вы сделали это?

vector<double> v;
cout << v << endl;

Компилятор не может определить, является ли G double или int в этом случае, потому что оба Chromosome<int> и Chromosome<double> имеют vector<double> как их вложенный тип.

Чтобы это исправить, вам придется явно использовать тип vector<G> в качестве аргумента:

template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome);

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

1 голос
/ 12 февраля 2011

Член typedef type является зависимым именем: его значение зависит от параметра шаблона G. Вам нужно использовать typename, чтобы сообщить компилятору, что type называет тип:

const typename Chromosome<G>::type&

Чтобы получить полное объяснение, прочитайте статью с часто задаваемыми вопросами о переполнении стека C ++, Где поместить «template» и «typename» на зависимые имена .

Как @templatetypedef упоминается в комментариях, хотя это позволит скомпилировать код, он не будет "работать", чтобы позволить вам вставить std::vector<G> в std::ostream, поскольку type находится в не выводимой контекст.

Самый простой способ объявить перегрузку и получить ожидаемое поведение - использовать std::vector<G> непосредственно в качестве типа аргумента:

template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome)
...