Оператор Typedef и ostream для std::vector
Вопрос
Я создал класс Chromosome, который в итоге оказался просто оберткой для вектора с оператором ostream, поэтому вместо этого я решил использовать typedef вектор.Однако у меня возникли проблемы с шаблонным оператором 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
Ваше здоровье.
Решение
К сожалению, нет чистого способа сделать это, поскольку компилятор не может определить тип 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);
К сожалению, лучшего способа сделать это действительно не существует.На самом деле это не недостаток языка, поскольку есть веская причина запретить его, но на самом деле это мешает вам делать то, что вы хотите в этом контексте.
Другие советы
Тип члена type
является зависимым именем:его значение зависит от параметра шаблона G
.Вам нужно использовать typename
сообщить компилятору, что type
называет тип:
const typename Chromosome<G>::type&
Для полного объяснения прочитайте статью часто задаваемых вопросов по Stack Overflow C++: Где разместить «шаблон» и «имя типа» для зависимых имен.
Как намекает @templatetypedef в комментариях, хотя это и позволит скомпилировать код, оно не «работает», чтобы позволить вам вставить std::vector<G>
в std::ostream
потому что type
находится в невыведенном контексте.
Самый простой способ объявить перегрузку и получить ожидаемое поведение — использовать std::vector<G>
непосредственно как тип аргумента:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome)