Pergunta

Criei uma classe Chromosome que acabou sendo simplesmente um wrapper para vector com um operador ostream, então decidi digitar vector em vez disso.No entanto, estou tendo problemas com o operador ostream modelado...Esta é a melhor maneira de fazer isso?(Vi algumas abordagens e não consegui fazer nenhuma funcionar)

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;
}

No momento o erro que estou recebendo é:

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

Saúde.

Foi útil?

Solução

Infelizmente, não há uma maneira limpa de fazer isso porque o compilador não consegue deduzir o tipo de G da declaração da função

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

A razão é que se você se especializar Chromosome para tipos diferentes, você pode acabar em uma situação em que o compilador não poderá inferir inequivocamente G.Por exemplo:

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;
};

Agora, o que aconteceria se você fizesse isso?

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

O compilador não pode dizer se G é double ou int neste caso, porque ambos Chromosome<int> e Chromosome<double> ter vector<double> como seu tipo aninhado.

Para corrigir isso, você terá que usar explicitamente o tipo vector<G> como o argumento:

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

Infelizmente, realmente não há uma maneira melhor de fazer isso.Não é realmente um defeito na linguagem, já que há uma boa razão para proibi-lo, mas na verdade impede você de fazer o que deseja neste contexto.

Outras dicas

O membro typedef type é um nome dependente:seu significado depende do parâmetro do modelo G.Você precisa usar um typename para dizer ao compilador que type nomeia um tipo:

const typename Chromosome<G>::type&

Para obter a explicação completa, considere a leitura do artigo Stack Overflow C++ FAQ, Onde colocar o “template” e o “typename” nos nomes dependentes.

Como @templatetypedef alude nos comentários, embora isso permita a compilação do código, não "funcionará" para permitir que você insira um std::vector<G> em um std::ostream porque type está em um contexto não deduzido.

A maneira mais fácil de declarar a sobrecarga e obter o comportamento esperado é usar std::vector<G> diretamente como o tipo de argumento:

template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top