C++ templates

9 respostas
renamed

Oi pessoal

To me aventurando por C++ e estou com dificuldades em templates
Dei uma olhada aqui http://www.cplusplus.com/doc/tutorial/templates/ mas não consegui fazer o que eu queria.

Eu estou fazendo uma classe chamada ListaEncadeada.

Em java, eu sei que podemos fazer

class ListaEncadeada<T extends Comparable<T>>

Como fazer algo assim em C++?

Meu .H atualmente está assim

template <class T>

class ListaEncadeada
{
    public:
        ListaEncadeada();
        ~ListaEncadeada();
        bool adicionar(T elem);


    private:
        unsigned int tamanho;
        T primeiro;
};

Outra coisa, no meu .cpp eu tive que colocar template <class T> antes de cada método, se eu tirar ele fala que T não existe naquele escopo. Existe alguma forma de só declarar esse T uma vez ou eu que estou fazendo algo errado mesmo? :lol:

template &lt;class T&gt;
ListaEncadeada&lt;T&gt;::ListaEncadeada(){

}

template &lt;class T&gt;
ListaEncadeada&lt;T&gt;::~ListaEncadeada(){
}

template &lt;class T&gt;
bool ListaEncadeada&lt;T&gt;::adicionar(T elem)
{
    return false;
}

Obrigado =D

9 Respostas

rodrigo.bossini

Acho que não entendi bem o que você não está conseguindo fazer, mas acho que esse trecho aqui pode lhe ser útil:

Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration. That means that we cannot separate the interface in a separate header file, and that we must include both interface and implementation in any file that uses the templates.

ViniGodoy

Não é necessário descrever o que o template extends, como no Java. No C++, se a “sintaxe” bater, o template poderá ser usado. Se não bater, não.
Por isso dizemos que os templates eliminam o sistema de tipos, e os generics restringem.

E não esqueça que templates normalmente são inteiramente implementados no .h.

renamed

Oi Rodrigo,
Então eu deveria colocar a implementação dos meus métodos no .H se eu quiser trabalhar com templates?

Oi Vini,
É porque eu queria colocar um método nessa classe que fizesse a ordenação dos elementos, então eu precisava que esse template só aceitasse classes que fossem filhas de uma classe que criei com um método abstrato que compara elementos, que nem java.
Você entendeu o que eu quis fazer? Acha que existe um jeito melhor?

Obrigado aos 2.

ViniGodoy

Sim.

Declare o tipo T e use qualquer método que você quiser, como se ele existisse.
O C++ irá autorizar qualquer classe que tenha esse método a usar sua lista, sem a necessidade de uma superclasse. :slight_smile:

O detalhe é que, quando alguém tentar usar sua classe, o C++ irá validar se o texto que você escreveu para a template bate com a estrutura da classe ou tipo primitivo para o qual vc tenta instanciar o tipo T.

Por exemplo, se você fizer assim:

template<typename T> bool menor(T obj1, T obj2) { return obj1 < obj2; }

Esse código funcionará para qualquer tipo primitivo, ou para qualquer tipo de usuário que tenha o operador de < sobrecarregado. Mas não funcionará caso esse operador não esteja lá (dá um erro de compilação).
Isso é muito flexível e mais poderoso do que os generics jamais sonham em ser.

Dica: Ao invés de um método, use o padrão do C++: o operador de <

ViniGodoy

Sim, com template vai tudo no .h.

ViniGodoy

Deixa eu te mostrar um exemplo mais concreto.

O template abaixo aceita qualquer classe que tenha o operador de < sobrecarregado, ou qualquer tipo primitivo ( o < é usado para fazer o ineficiente, mas útil para nosso exemplo, "bubble sort"):
#if !defined(__LISTA_H__)
#define __LISTA_H__

#include &lt;vector&gt;
#include &lt;iostream&gt;

template &lt;typename T&gt;
class Lista
{
	private:
		std::vector&lt;T&gt; elements;
	public:
		void add(T elem)
		{
			elements.push_back(elem);
		}

		void sort()
		{
			for (unsigned i = 0; i &lt; elements.size()-1; ++i)
				for (unsigned j = i+1; j &lt; elements.size(); ++j)
					if (elements[i] &gt; elements[j])
						std::swap(elements[i], elements[j]);
		}

		void print() const
		{
			for (unsigned i = 0; i &lt; elements.size(); ++i)			
				std::cout &lt;&lt; elements[i] &lt;&lt; &quot; &quot;;
			std::cout &lt;&lt; std::endl;
		}
};
#endif

Note que a lista funciona para o tipo primitivo int (pois ele funciona com o <) e para a classe String, já que ela também tem o < sobrecarregado:

#include &quot;Lista.h&quot;
#include &lt;string&gt;

int main(int argc, char* argv[])
{
	Lista&lt;int&gt; lista;
	lista.add(10);
	lista.add(2);
	lista.add(7);
	lista.add(2);
	lista.add(3);
	lista.add(7);
	lista.sort();
	lista.print();

	Lista&lt;std::string&gt; lista2;
	lista2.add(&quot;Pera&quot;);
	lista2.add(&quot;Banana&quot;);
	lista2.add(&quot;Laranja&quot;);
	lista2.add(&quot;Abacaxi&quot;);
	lista2.sort();
	lista2.print();
}

Na verdade, você pode até mesmo usar a lista sem o operador de < sobrecarregado, desde que jamais chame o método sort() - pois ele é único que exige o operador de <.
Quando estiver usando templates, simplesmente escreva o código que você pretenda que o tipo T respeite, e ele será obrigado a respeitar.

Note também que, diferente do Java, não há necessidade de herança. Com templates, você tem typesafety mas sem restrições de tipo.
O generic tem o objetivo oposto. Aumentar typesafety através de restrições de tipo (antes dele, você tinha que fazer uma lista de Object, que não impunha restrição nenhuma, mas era unsafe).

renamed

Oi Vini

Ajudou MUITO mesmo!
Eu comecei a testar a aplicação, consegui fazer uma lista de inteiros, na hora que criei uma classe Pessoa ele reclamou, foi só sobrecarregar o operador == que ele parou de reclamar.

Obrigadão mesmo!

class Pessoa
{
    public:
        bool operator==(Pessoa p1)
        {
            return idade == p1.idade;
        }

        int idade;
};
ViniGodoy
Troque o parâmetro do operador para const Pessoa&. Isso evita cópia. É uma boa declara-lo como const também.
class Pessoa
{
    public:
        bool operator==(const Pessoa& p1) const
        {
            return idade == p1.idade;
        }

        int idade;
};
renamed

OK Vini

Mais uma vez mto obrigado.

Criado 12 de novembro de 2011
Ultima resposta 13 de nov. de 2011
Respostas 9
Participantes 3