[Resolvido] problema ao sobrecarregar uma funcao global com uma template de funcao

7 respostas
DavidUser
tive problemas ao tentar a seguinte sobrecarga de função:
template <typename T, int numberOfElements>
// operador de entrada sobrecarregado para a classe Array;
// entrada de valores para o Array
istream &operator>>( istream &input, Array<T, numberOfElements> &a )
{
   for ( int i = 0; i < a.size; i++ )
      input >> a.ptr[ i ];

   return input; // permite cin >> x >> y;
} // fim da fun��o

template <typename T, int numberOfElements>
// operador de sa�da sobrecarregado para classe Array
ostream &operator<<( ostream &output, const Array<T, numberOfElements> &a )
{
   int i;

   // gera sa�da do array baseado em ptr private
   for ( i = 0; i < a.size; i++ )
   {
      output << setw( 12 ) << a.ptr[ i ];

      if ( ( i + 1 ) % 4 == 0 ) // 4 n�meros por linha de sa�da
         output << endl;
   } // fim do for

   if ( i % 4 != 0 ) // termina a �ltima linha de sa�da
      output << endl;

   return output; // permite cout << x << y;
} // fim da fun��o operator<<

queria entender se o meu pensamento está correto e gostaria se alguém me explicasse melhor, uma função que foi sobrecarregada dá prioridade as funções não-template então os operadores padrão do c++ "<<" e ">>" tem funções não-template que já possui um argumento do tipo do meu objeto?

Ao tentar a sobrecarga tudo segue normalmente mas ao utilizar o operador a sobrecarga não tem efeito.

7 Respostas

E

Estranho. O código abaixo compilou e executou (de acordo com o que você estava imaginando) corretamente:

#include <iostream>
#include <string>

using namespace std;
template <typename T, int n>
class Array {
public:
    T t[n];
};

template <typename T, int n> 
ostream& operator<< (ostream& out, const Array<T, n>& a) {
    for (int i = 0; i < n; ++i) {
	    out << a.t[i] << " ";
	}
	return out;
}

int main (int argc, char *argv[]) {
    Array<int, 20> x;
	for (int i = 0; i < 20; i++) 
	    x.t[i] = i;
	cout << x;
}

Não sei o que pode ter dado de errado no seu código, porque você não postou tudo. O que pude reproduzir a partir do seu código parece ter funcionado direitinho.

DavidUser

no meu código as funções são friends da classe.

e invés de pegar o tamanho direto do parâmetro do template de função pega o size da matriz direto no atributo privado e percorro o array direto do ponteiro privado.
istream &operator>>( istream &input, Array<T, numberOfElements> &a )
{
   for ( int i = 0; i < a.size; i++ )
      input >> a.ptr[ i ];
minha classe array tem o ponteiro e o atributo size privados:
template <typename T, int numberOfElements = 10>
class Array
{
   friend ostream &operator<<( ostream &, const Array<T, numberOfElements> & );
   friend istream &operator>>( istream &, Array<T, numberOfElements> & );
public:
   Array(){};
   int getSize() const; // retorna tamanho

   const Array<T, numberOfElements> &operator=( const Array<T> & ); // operador de atribui&#65533;&#65533;o
   bool operator==( const Array<T, numberOfElements> & ) const; // operador de igualdade

   // operador de desigualdade; retorna o oposto do operador ==
   bool operator!=( const Array<T, numberOfElements> &right ) const
   {                                                         
      return ! ( *this == right ); // invoca Array::operator==
   } // fim da fun&#65533;&#65533;o operator!=                             
   
   // operador subscrito de objetos n&#65533;o-const retorna lvalue modific&#65533;vel
   T &operator[]( int );

   // operador de subscrito de objetos const retorna rvalue
   T operator[]( int ) const;
private:
   int size; // tamanho do array baseado em ponteiro
   int ptr[numberOfElements]; // ponteiro para o primeiro elemento do array baseado em ponteiro
}; // fim da classe Array
E

Você não declarou corretamente o friend operator. A declaração correta (que compila corretamente com o g++ 4.3 e com o MS Visual Studio 2008) é algo como (novamente usando meu exemplo):

#include <iostream>
#include <string>

using namespace std;
template <typename T, int n>
class Array {
public:
    Array() {
	    for (int i = 0; i < n; ++i) t[i] = i;
	}
public:
	template <typename U, int m> friend ostream& operator<< (ostream& out, const Array<U, m>& a);
private:
    T t[n];
};

template <typename T, int n> 
ostream& operator<< (ostream& out, const Array<T, n>& a) {
    for (int i = 0; i < n; ++i) {
	    out << a.t[i] << " ";
	}
	return out;
}

int main (int argc, char *argv[]) {
    Array<int, 20> x;
	cout << x;
}

Note que o g++ não aceita que eu conserve o mesmo nome para o parâmetro do template (tive de usar U e m).

DavidUser

Muito Obrigado entanglement estou lendo o Deitel onde não havia um exemplo para essa situação, mas creio que então que template &lt;typename U, int m&gt; faz parte do cabeçalho da função e como a declaração friend na classe depende de um protótipo de função…

Entendi certo? Quando declaro uma template de função o cabeçalho de template também faz parte do cabeçalho de função?

DavidUser

Funcionando bem, agora ficou assim:

template &lt;typename T, int numberOfElements = 10&gt;
class Array
{
   template &lt;typename U, int n&gt; friend ostream &operator&lt;&lt;( ostream &, const Array&lt;U, n&gt; & );
   template &lt;typename U, int n&gt; friend istream &operator&gt;&gt;( istream &, Array&lt;U, n&gt; & );
public:
   Array(): size(numberOfElements){};
   int getSize() const; // retorna tamanho

   const Array&lt;T, numberOfElements&gt; &operator=( const Array&lt;T&gt; & ); // operador de atribui&#65533;&#65533;o
   bool operator==( const Array&lt;T, numberOfElements&gt; & ) const; // operador de igualdade

   // operador de desigualdade; retorna o oposto do operador ==
   bool operator!=( const Array&lt;T, numberOfElements&gt; &right ) const
   {                                                         
      return ! ( *this == right ); // invoca Array::operator==
   } // fim da fun&#65533;&#65533;o operator!=                             
   
   // operador subscrito de objetos n&#65533;o-const retorna lvalue modific&#65533;vel
   T &operator[]( int );

   // operador de subscrito de objetos const retorna rvalue
   T operator[]( int ) const;
private:
   int size; // tamanho do array baseado em ponteiro
   int ptr[numberOfElements]; // ponteiro para o primeiro elemento do array baseado em ponteiro
}; // fim da classe Array
[size=18] Entendi certo? Quando declaro uma template de função o cabeçalho de template também faz parte do cabeçalho de função?[/size]
E

De certo modo sim.
Realmente você teria dificuldade de achar um exemplo desses no Deitel, já que ele expõe uma sutileza da linguagem que nem é muito bem implementada em todos os compiladores.
Se você tem intimidade com leitura de especificações de linguagens de programação (é algo semelhante a ler um livro de Direito Tributário e de matemática avançada ao mesmo tempo, já que tem um monte de coisas arbitrárias e que não fazem sentido à primeira vista), então pode tentar achar isso na definição da linguagem C++. Talvez você possa encontrar isso mais ou menos explicado em: http://www2.research.att.com/~bs/arm.html - este é o livro carinhosamente chamado de “ARM” pela comunidade C++.

Para ver como você quer usar um caso pouco usado da linguagem (operadores “friend” em um template), basta ver que o código que postei não compila corretamente no Visual Studio 2005 ( o código que compila no 2005 não compila no g++ 4.3, nem no 2008, e vice-versa ).

Um conselho: se puder, evite usar recursos da linguagem C++ que possam ter problemas de compilação. Eu tenho os 3 compiladores na minha máquina, e foi por isso que consegui ver que isso é algo difícil de usar.

DavidUser

Muito Obrigado pela ajuda e atenção entanglement!
Vou procurar este livro

Criado 2 de agosto de 2011
Ultima resposta 5 de ago. de 2011
Respostas 7
Participantes 2