Ir ao conteúdo
  • Cadastre-se
Cambalinho

é possivel fazer 1 tipo de variavel que aceite qualquer tipo?

Recommended Posts

Bom, se você quiser criar uma função ou função membro que aceite qualquer tipo de variável, então estamos falando de funções template.

Por exemplo, uma função soma que some dois números, sejam eles int, double, float (e nesse caso até variáveis do tipo char e string seriam aceitas embora o comportamento da função poderia ser anômalo):


template <class [COLOR="Blue"]minha_variavel[/COLOR]>
[COLOR="blue"]minha_variavel[/COLOR] soma([COLOR="blue"]minha_variavel[/COLOR] a, [COLOR="blue"]minha_variavel[/COLOR]
{
return (a + ;
}

Nesse código minha_variavel é uma variável que aceitará qualquer tipo. Bom, na verdade ela não aceita qualquer tipo, simplesmente na hora de compilar, o compilador cria uma especialização dessa função (sua versão int ou double ou float ou o que quer que seja) em cada caso em que ela for invocada.

Veja que o próprio tipo da função também é genérico.

Mais infos: http://www.cplusplus.com/doc/tutorial/templates/

Compartilhar este post


Link para o post
Compartilhar em outros sites
Bom, se você quiser criar uma função ou função membro que aceite qualquer tipo de variável, então estamos falando de funções template.

Por exemplo, uma função soma que some dois números, sejam eles int, double, float (e nesse caso até variáveis do tipo char e string seriam aceitas embora o comportamento da função poderia ser anômalo):


template <class [COLOR="Blue"]minha_variavel[/COLOR]>
[COLOR="blue"]minha_variavel[/COLOR] soma([COLOR="blue"]minha_variavel[/COLOR] a, [COLOR="blue"]minha_variavel[/COLOR]
{
return (a + ;
}

Nesse código minha_variavel é uma variável que aceitará qualquer tipo. Bom, na verdade ela não aceita qualquer tipo, simplesmente na hora de compilar, o compilador cria uma especialização dessa função (sua versão int ou double ou float ou o que quer que seja) em cada caso em que ela for invocada.

Veja que o próprio tipo da função também é genérico.

Mais infos: http://www.cplusplus.com/doc/tutorial/templates/

muito obrigado, mas posso fazer isso independente?

ou seja para ser utilizado em qualquer sitio\funçao\variavel?

eu fiz este codigo dentro da class Console(eu estou a usar NULL, para os proximos argumentos serem optionais;)):

template<class variant>
void Write(variant var1, variant var2=NULL, variant var3=NULL, variant var4=NULL, variant var5=NULL, variant var6=NULL)
{
cout << var1 << var2 << var3 << var4 << var5 << var6;
}

mas noto problemas:(

porque a variavel nao aceita qualquer tipo\outra variavel:(

eis como a uso:

#include <iostream>
#include <conio.h>
#include "Console.h"


using namespace std;


int main(int argc, char** argv)
{
Console a;
int c=10;
a.Write(10);
getch();
return 0;
}

se meter 1 texto da-me erro e ás vezes se meter o 'c' tambem:(

alem disso o NULL esta-me a mostrar '0', mas eu nao quero isso:(

algumas dicas por favor?

Compartilhar este post


Link para o post
Compartilhar em outros sites
muito obrigado, mas posso fazer isso independente?

ou seja para ser utilizado em qualquer sitio\funçao\variavel?

Sim. Na verdade é um recurso muito poderoso. Até classes inteiras podem ser feitas usando templates.

eu fiz este codigo dentro da class Console(eu estou a usar NULL, para os proximos argumentos serem optionais;)):

template<class variant>
void Write(variant var1, variant var2=NULL, variant var3=NULL, variant var4=NULL, variant var5=NULL, variant var6=NULL)
{
cout << var1 << var2 << var3 << var4 << var5 << var6;
}

mas noto problemas:(

porque a variavel nao aceita qualquer tipo\outra variavel:(

eis como a uso:

#include <iostream>
#include <conio.h>
#include "Console.h"


using namespace std;


int main(int argc, char** argv)
{
Console a;
int c=10;
a.Write(10);
getch();
return 0;
}

se meter 1 texto da-me erro e ás vezes se meter o 'c' tambem:(

alem disso o NULL esta-me a mostrar '0', mas eu nao quero isso:(

algumas dicas por favor?

Bom, vamos lá. Não sou um especialista mas parece que você cometeu alguns errinhos.

Primeiro, quando você criou o tipo genérico variant, e declarou varias variáveis (var1, var2 etc.) do tipo variant, você está implicitamente dizendo que todas tem o mesmo tipo. Então todas devem ser int, ou todas devem ser double etc. Se não é o que você esperava, então, o que se deve fazer nesse caso é declarar varias variáveis do tipo variant:


template<class [COLOR="Blue"]variant1[/COLOR], class [COLOR="blue"]variant2[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2)
{
}

Segundo, você declarou e imediatamente após as definiu por default igual a NULL. Variáveis genéricas não podem ser inicializadas por default em compiladores mais antigos. De fato, isso só é possível na nova versão do C++, o C++11. Você deveria consultar a documentação do compilador pra saber se ele te permite fazer isso.

Terceiro, supondo que você não possa inicializar por default, a solução que eu sugeriria seria uma função template (que você já tem) sobrecarregada. Ou seja:


template<class [COLOR="Blue"]variant1[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1)
{
}

template<class [COLOR="blue"]variant1[/COLOR], class [COLOR="blue"]variant2[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2)
{
}

template<class [COLOR="blue"]variant[/COLOR]1, class [COLOR="blue"]variant2[/COLOR], class [COLOR="blue"]variant3[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2, [COLOR="blue"]variant3[/COLOR] var3)
{
}

// até...

template<class [COLOR="blue"]variant1[/COLOR], class [COLOR="blue"]variant2[/COLOR], class [COLOR="blue"]variant3[/COLOR], /* ... */ class [COLOR="blue"]variant6[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2, [COLOR="blue"]variant3[/COLOR] var3, /* ...*/ [COLOR="blue"]variant6[/COLOR] var6)
{
}

Pra cada uma das possíveis funções Write(), você declara e define uma com o numero de argumentos que ela possa aceitar até atingir o numero máximo de argumentos que você quer, 6 nesse caso. Assim você garante que se invocar Write(10) ou Write(10, 11) ou mesmo Write(11, 12, 1.0) e até mesmo Write("olá mundo!", "eu sou o argumento 2", 1.0, 0.09847); ela existirá e será uma função 100% funcional.

EDIT: Quase esqueço algo bastante importante: Coisas genéricas como templates devem ser declaradas e também definidas no cabeçario .h, heim! Porque o compilador deve ver diretamente como implementar cada especialização da função quando encontrar cada chamada dela código afora.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Sim. Na verdade é um recurso muito poderoso. Até classes inteiras podem ser feitas usando templates.

Bom, vamos lá. Não sou um especialista mas parece que você cometeu alguns errinhos.

Primeiro, quando você criou o tipo genérico variant, e declarou varias variáveis (var1, var2 etc.) do tipo variant, você está implicitamente dizendo que todas tem o mesmo tipo. Então todas devem ser int, ou todas devem ser double etc. Se não é o que você esperava, então, o que se deve fazer nesse caso é declarar varias variáveis do tipo variant:


template<class [COLOR="Blue"]variant1[/COLOR], class [COLOR="blue"]variant2[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2)
{
}

Segundo, você declarou e imediatamente após as definiu por default igual a NULL. Variáveis genéricas não podem ser inicializadas por default em compiladores mais antigos. De fato, isso só é possível na nova versão do C++, o C++11. Você deveria consultar a documentação do compilador pra saber se ele te permite fazer isso.

Terceiro, supondo que você não possa inicializar por default, a solução que eu sugeriria seria uma função template (que você já tem) sobrecarregada. Ou seja:


template<class [COLOR="Blue"]variant1[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1)
{
}

template<class [COLOR="blue"]variant1[/COLOR], class [COLOR="blue"]variant2[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2)
{
}

template<class [COLOR="blue"]variant[/COLOR]1, class [COLOR="blue"]variant2[/COLOR], class [COLOR="blue"]variant3[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2, [COLOR="blue"]variant3[/COLOR] var3)
{
}

// até...

template<class [COLOR="blue"]variant1[/COLOR], class [COLOR="blue"]variant2[/COLOR], class [COLOR="blue"]variant3[/COLOR], /* ... */ class [COLOR="blue"]variant6[/COLOR]>
void Write([COLOR="blue"]variant1[/COLOR] var1, [COLOR="blue"]variant2[/COLOR] var2, [COLOR="blue"]variant3[/COLOR] var3, /* ...*/ [COLOR="blue"]variant6[/COLOR] var6)
{
}

Pra cada uma das possíveis funções Write(), você declara e define uma com o numero de argumentos que ela possa aceitar até atingir o numero máximo de argumentos que você quer, 6 nesse caso. Assim você garante que se invocar Write(10) ou Write(10, 11) ou mesmo Write(11, 12, 1.0) e até mesmo Write("olá mundo!", "eu sou o argumento 2", 1.0, 0.09847); ela existirá e será uma função 100% funcional.

EDIT: Quase esqueço algo bastante importante: Coisas genéricas como templates devem ser declaradas e também definidas no cabeçario .h, heim! Porque o compilador deve ver diretamente como implementar cada especialização da função quando encontrar cada chamada dela código afora.

desculpa, mas ate esse ponta ja sabia.

só que em vez de criar funçoes para cada parametro. posso transformar

"template<class variant>" de tal forma que use esta sintax:

(parece que NULL é zero lol)

void Write(variant var1, variante var2="", variante var3="")

???

será que posso fazer isso? e assim usava variante em qualquer local;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

void Write(variant var1, variante var2="", variante var3="")

Eu acho que não, porque como você volta a definir todas as variáveis com o mesmo tipo, variant, então obrigatoriamente todas as variáveis devem ser do mesmo tipo. Ou seja todas int ou todas double ou todas float etc.

E se você as inicializa por default com

variante var2 = ""

Então as variáveis DEVEM ser char ou string, porque você deve saber que números não se inicializam assim.

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante

é possivel criar 1 variavel que aceite qualquer tipo de dados?

Por exemplo' date=' uma função soma que some dois números, sejam eles int, double, float (e nesse caso até variáveis do tipo char e string seriam aceitas embora [b']o comportamento da função poderia ser anômalo):

Olá,

No caso explícito, uma variável ou função deve ser definida para o seu devido propósito.

Não há lógica em fazer operações matemáticas em variáveis strings, ou escrever caracteres em variáveis numéricas.

  • Curtir 1

Compartilhar este post


Link para o post
Compartilhar em outros sites
Olá,

No caso explícito, uma variável ou função deve ser definida para o seu devido propósito.

Não há lógica em fazer operações matemáticas em variáveis strings, ou escrever caracteres em variáveis numéricas.

Sim, claro. Aquele comentário foi só pra exemplificar que absolutamente tudo poderia ser aceito. Mas não há necessidade dessas coisas.

Por exemplo, os tutoriais sobre esse assunto sempre trazem o exemplo canônico de um código que compara dois números (maior ou menor que), e sempre mostram também o que acontece quando colocamos, por exemplo, uma string. Foi o que eu eu tentei dizer pro autor do tópico.

Compartilhar este post


Link para o post
Compartilhar em outros sites

desculpem. mas vejam este codigo que estou a tentar usar:

class any {
public:
// construct/copy/destruct
any();
any(const any &);
any(any &&);//i get several errors inclued these line:(
template<typename ValueType> any(const ValueType &);
template<typename ValueType> any(ValueType &&);
any & operator=(const any &);
any & operator=(any &&);
template<typename ValueType> any & operator=(const ValueType &);
template<typename ValueType> any & operator=(ValueType &&);
~any();

// modifiers
any & swap(any &);

// queries
bool empty() const;
const std::type_info & type() const;
};

só nao o consigo usar:(

mas nao dá erro.

eu ja posso usar o C++ 11;)

alguem me pode dizer se mesmo assim nao posso criar variaveis daquela forma?

(eu usei como strings vazias para ter argumentos optionais;))

o meu objectivo é construir a funçao write() desta forma:

Write( variant var1[, variant var2=", variant varx="])

muito obrigado por me ajudarem

Compartilhar este post


Link para o post
Compartilhar em outros sites

finalmente criei o meu tipo variant:

class variant
{

string a="";
public:


friend istream& operator >>(istream &is,variant &obj)
{
is>>obj.a;
return is;
}

friend ostream& operator <<(ostream &os,const variant &obj)
{
os<<obj.a;
return os;
}

friend istream &getline(istream &in, variant &s1)
{
getline(in, s1.a);
return in;
}


variant & operator = (int const &
{
a=to_string(;
return *this;
}

variant & operator = (string const &
{
a=b;
return *this;
}

variant & operator = (double const &
{
a=to_string(;
return *this;
}

variant & operator = (float const &
{
a=to_string(;
return *this;
}

string & operator = (variant const &
{

return a;
}

};

e funciona. mas imagina que 1 string\int\float\double recebe 1 valor da minha variavel.

por isso tenho:

string & operator = (variant const & 
{

return a;
}

mas da-me varios erros:(

como posso alterar a minha class para poder fornecer string\double\int?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Você poderia criar templates com um tipo de retorno genérico.


template <typename [COLOR="blue"]tipo[/COLOR]>
[COLOR="blue"]tipo[/COLOR] &operator = (variant const &

E na hora de usar você diz que tipo ele deve retornar:

std::string a =<std::string> b;

Ou esquematizar um sistema de IDs pra cada tipo dentro de variant, ou mais elegantemente uns booleans. De maneira que a classe saiba que tipo de variável tem dentro de si próprio (no caso, que saiba o tipo original de b antes de ter sido convertido a variant).

E ai dependendo da ID (tipo) você chama uma determinada função pra retornar-la. Seu problema daí em diante será apenas desenhar essa função (talvez não seja trivial se forem templates porque será difícil do código saber que tipo retornar na hora de criar as funções especializadas na compilação, afinal nesse momento as ID são ainda inúteis).

Compartilhar este post


Link para o post
Compartilhar em outros sites
Você poderia criar templates com um tipo de retorno genérico.


template <typename [COLOR="blue"]tipo[/COLOR]>
[COLOR="blue"]tipo[/COLOR] &operator = (variant const &

E na hora de usar você diz que tipo ele deve retornar:

std::string a =<std::string> b;

Ou esquematizar um sistema de IDs pra cada tipo dentro de variant, ou mais elegantemente uns booleans. De maneira que a classe saiba que tipo de variável tem dentro de si próprio (no caso, que saiba o tipo original de b antes de ter sido convertido a variant).

E ai dependendo da ID (tipo) você chama uma determinada função pra retornar-la. Seu problema daí em diante será apenas desenhar essa função (talvez não seja trivial se forem templates porque será difícil do código saber que tipo retornar na hora de criar as funções especializadas na compilação, afinal nesse momento as ID são ainda inúteis).

ja resolvi essa situaçao;)

class variant
{
string a="";
public:

variant (string value="")
{
a=value;
}

variant (double value)
{
a=to_string(value);
}

friend istream& operator >>(istream &is,variant &obj)
{
is>>obj.a;
return is;
}

friend ostream& operator <<(ostream &os,const variant &obj)
{
os<<obj.a;
return os;
}

friend istream &getline(istream &in, variant &s1)
{
getline(in, s1.a);
return in;
}


variant & operator = (int const &
{
a=to_string(;
return *this;
}

variant & operator = (string const &
{
a=b;
return *this;
}

variant & operator = (double const &
{
a=to_string(;
return *this;
}

variant & operator = (float const &
{
a=to_string(;
return *this;
}

bool operator == (string const &
{

return (a==;
}

operator string() const
{
return a; // return string member
}

operator double() const
{
return atof(a.c_str()) ;
}

};

int main()
{
variant a=(string)"hello world";
string b=a;
cout << b;
getch();//conio.h
}

(usar o '(string)' deve ser por causa da string... mas funciona)

muito obrigado

ainda tenho algumas coisas a fazer como '+' e comparações;)

mas esta fixe.

diz-me o que pensas desta class?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora





Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas publicações sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×