Typedef и ostream оператор за std::vector

Създадох клас Chromosome, който в крайна сметка беше просто обвивка за вектор с оператор ostream, така че вместо това реших да напиша вектор. Имам обаче проблем с шаблонния оператор 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

наздраве


person Rhys van der Waerden    schedule 12.02.2011    source източник


Отговори (2)


За съжаление, няма чист начин да направите това, защото компилаторът не може да изведе типа на 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);

За съжаление наистина няма по-добър начин да направите това. Това всъщност не е дефект в езика, тъй като има основателна причина да го забраните, но всъщност ви пречи да правите това, което искате в този контекст.

person templatetypedef    schedule 12.02.2011
comment
Благодаря, сега разбирам как работи това. използването на вектор е напълно добре, тъй като се опитвах да използвам Chromosome‹G›::type само за четливост. Бихте ли обяснили, че тук не е необходимо име на тип? - person Rhys van der Waerden; 13.02.2011

Членът typedef type е зависимо име: значението му зависи от параметъра на шаблона G. Трябва да използвате typename, за да кажете на компилатора, че type назовава тип:

const typename Chromosome<G>::type&

За пълното обяснение можете да прочетете статията с често задавани въпроси за Stack Overflow 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)
person James McNellis    schedule 12.02.2011
comment
Всъщност това няма да работи, защото компилаторът не може да изведе G в този контекст. Това отчасти е така, защото можете да създадете някои ситуации със специализация на шаблони, при които компилаторът не може да знае кой тип да използва. - person templatetypedef; 12.02.2011
comment
@templatetypedef: Добра точка; зависимото име не е единственият проблем тук. - person James McNellis; 12.02.2011
comment
Благодаря за отговора, открих, че templatetypedef е малко по-ясен, така че той получава този. - person Rhys van der Waerden; 13.02.2011