reticencias e & [RESOLVIDO]

1. reticencias e & [RESOLVIDO]

john kevin de souza
john1710

(usa Ubuntu)

Enviado em 06/08/2017 - 03:07h

Fala galera, eu estudei POO em java e recentemente fui estudar c++, porem estava vendo um video em inglês, não entendo bem o idioma e tive muitas dificuldades, assim como coisas que nunca sequer imaginei que existisse. e vim pedir que se pudessem, esclarecem minhas duvidas.
durante o video me deparei com a criação dessa função.
template<typename T,typename... TArgs>
T& addComponent(TArgs&&... mArgs){}

minhas duvidas são:
1- quando eu crio o template, qual a diferença de usar class T e typename T,?
2- o que significa reticencias.
3- e nesse caso dentro do parametro template, porque tem esse "typename... Targs" ?
4- porque o retorno é "T&" o que é esse T&?
5- e como paremetro de função, o que é "Targs&&... mArgs" denovo o que ser essas reticencias e esses dois &&??
obs: eu li em alguns artigos que reticencias em c++ queria dizer que viriam varios parametros, se for verdade como eu vou tratar esses varios parametros dentro da função?



  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 07/08/2017 - 04:36h

john1710 escreveu:

Fala galera, eu estudei POO em java e recentemente fui estudar c++, porem estava vendo um video em inglês, não entendo bem o idioma e tive muitas dificuldades, assim como coisas que nunca sequer imaginei que existisse. e vim pedir que se pudessem, esclarecem minhas duvidas.
durante o video me deparei com a criação dessa função.
template<typename T,typename... TArgs>
T& addComponent(TArgs&&... mArgs){}

minhas duvidas são:
1- quando eu crio o template, qual a diferença de usar class T e typename T,?


Nesse caso, nenhuma.

Quando o C++ introduziu templates na linguagem, a forma de usar era sempre “template <class T> definição_da_função_ou_classe_usando_T”. Contudo, algumas pessoas achavam estranho usar “class” quando o argumento do template era um tipo nativo, em vez de um tipo definido pelo usuário (classes, estruturas, uniões, enumerações etc.). Então o padrão de 1998 decidiu que, no contexto de templates, as duas palavras poderiam ser usadas indistintamente, tanto para tipos nativos como para tipos definidos pelo usuário. (Aliás, uma diferença entre templates do C++ e Generics do Java é justamente poder ser usado com tipos nativos.)

As duas declarações abaixo são sinônimas, indicando uma função que recebe, por referência constante, dois argumentos do mesmo tipo, e devolve o valor do maior deles.

template <class T> T max(const T &x, const T &y){ return x<y? y: x; } 

template <typename T> T max(const T &x, const T &y){ return x<y? y: x; } 


Um outro tipo de argumento que pode ser passado para um template é um valor constante de um tipo nativo. Nesse caso, em lugar de “class” ou “typename”, você usa a designação do nome do tipo. Por exemplo, você pode criar uma classe para representar matrizes em que a dimensão é um parâmetro inteiro amarrado em tempo de compilação, através de template. Isso permitiria ao compilador identificar operações ilegais com matrizes de dimensões incompatíveis.

// Classe que representa uma matriz.
template <unsigned ROWS, unsigned COLS> class Matrix { /* ... */ };

// Operador de soma de matrizes.
template <unsigned R, unsigned C> Matrix<R, C> operator +(const Matrix<R, C> &m1, const Matrix<R, C> &m2){ /* ... */}

// Operador de produto de matrizes.
template <unsigned R1, unsigned C1R2, unsigned C2> Matrix<R1, C2> operator *(const Matrix<R1, C1R2> &m1, const Matrix<C1R2, C2> &m2){ /* ... */}

// Exemplos de uso
void f(){
Matrix<3, 4> a, b, c;
Matrix<4, 5> d;
Matrix<3, 5> e;

c=a+b; // OK: todas as matrizes têm dimensões compatíveis com a soma.
d=a+b; // Erro de compilação: d não é compatível com o tipo retornado pela soma.
d=a*b; // Erro de compilação: a e b não têm dimensões compatíveis com o produto.
e=a*d; // OK: nº cols de a==nº lins de d, e dimensões de e são nº lins de a e nº cols de d.
}


2- o que significa reticencias.


Reticências existem desde priscas eras no C. Antigamente elas eram usadas apenas com funções, indicando que elas podiam receber uma quantidade variável de argumentos (VAL, de variable argument list).

Tal uso de funções com lista de argumentos variável também foi adotado pelo C++, por causa da compatibilidade com C, mas tinha um sério problema do ponto de vista do C++: a verificação de tipos não apenas não funciona com VALs, mas VALs ainda impõem regras para forçosamente modificar os tipos de alguns argumentos.

Uma parte das inconveniências do C podia ser contornada com polimorfismo, particularmente com sobrecarga de funções (i.e. funções com o mesmo nome, mas com argumentos diferentes). Mas o caso mais geral, em que a lista de argumentos podia realmente variar bastante na quantidade de argumentos, dependia de algo mais, e isso levou ao aparecimento de templates com quantidade variável de argumentos, padronizada no C++11.

O caso que você trouxe é um caso de template com lista de argumentos variável. Ela geralmente trabalha, no caso de templates de classes. junto com especializações, e com sobrecarga de funções, no caso de templates de funções e operadores.

3- e nesse caso dentro do parametro template, porque tem esse "typename... Targs" ?


Para indicar:

a) que há múltiplos argumentos para o template daquele ponto em diante (“...”),

b) que tais argumentos designam tipos (“typename”), e

c) a forma de referir-se a esses elementos numa eventual expansão do VAL é através do nome “Targs”.

4- porque o retorno é "T&" o que é esse T&?


T é um dos argumentos do template, que não faz parte da bloco de argumentos variáveis e que designa um tipo.

T& significa “referência para dado do tipo T”. Esse tipo T& está sendo usado para designar o tipo de retorno de uma função chamada addComponent() (ou seja, quando essa função for invocada, o resultado será do tipo “referência para valor do tipo T”).

5- e como paremetro de função, o que é "Targs&&... mArgs" denovo o que ser essas reticencias e esses dois &&??


Quando as reticências aparecem após o nome do argumento que designa o VAL do template, você indica uma expansão do VAL em seus componentes. No seu caso, como o nome Targs é um VAL de tipos de dados, a expansão será uma outra VAL, só que agora para designar os objetos dos respectivos tipos da primeira VAL.

Talvez um exemplo ajude (N.B. eu sei que o exemplo é meio tosco, porque poderia muito bem ser feito sem templates, e ainda mais sem VAL, e também porque introduzo uma referência desnecessária apenas para mostrar como ela aparece numa das etapas de expansão, e acabo não a usando no final; mesmo assim, creio que vai servir para entender como são feitas as expansões).

class generic_point { };

class point2d: public generic_point {
public:
point2d(double, double);
};

class point3d: public generic_point {
public:
point3d(double, double, double);
};

class point_list {
public:
void add(generic_point *pt);
/* bla, bla, bla */
};

template <class T, class... T_Components>
T *makepoint(const T_Components &... components){
return new T(components...);
}

void f(){
point_list pl;

pl.add(makepoint<point2d>(0.0, 1.0));
/*
1ª expansão: T=point2d, T_Components=“double, double”.
*/
/*
2ª expansão: cria função
“point2d *makepoint(const double &arg1, const double &arg2)” (arg1 e
arg2 são nomes fictícios, só para efeito de explicação).
components corresponde à lista formada pelos valores dos argumentos.
*/
/*
3ª expansão: expande components, chamando o construtor de point2d
com os valores dos argumentos “arg1, arg2”.
*/

pl.add(makepoint<point3d>(-1, 2.2, -3.3));
/*
1ª expansão: T=point3d, T_Components=“int, double, double” (o primeiro
argumento é do tipo int; a conversão de int para double será feita mais
tarde).
*/
/*
2ª expansão: cria função
“point3d *makepoint(const int &arg1, const double &arg2, const double &arg3)”
(arg1 arg2 e arg3 são nomes fictícios, só para efeito de explicação).
components corresponde à lista formada pelos valores dos argumentos.
*/
/*
3ª expansão: expande components, chamando o construtor de point3d
com os valores dos argumentos “arg1, arg2, arg3”. Como point3d só
tem um construtor com os três argumentos do tipo double e a conversão
de int para double pode ser feita automaticamente, o arg1 é convertido
para double neste ponto.
*/
}


O exemplo acima mostra que, na segunda expansão, eu gerei referências constantes (e.g. “const int &” e “const double &”). Se eu quisesse (e se fizesse sentido), eu poderia ter usado referências para rvalues, indicadas pelo token &&.

Referências para rvalues são muito bem explicadas, quase que num passo-a-passo, e muito bem escrito, em http://thbecker.net/articles/rvalue_references/section_01.html (em Inglês).

obs: eu li em alguns artigos que reticencias em c++ queria dizer que viriam varios parametros, se for verdade como eu vou tratar esses varios parametros dentro da função?


Geralmente o que acontece é que você tem uma parte dos argumentos do template que é não-VAL, e outra parte que é VAL. Os dois usos mais comuns são:

1) Usar os argumentos não-VAL para escolher uma classe ou função específica, e fazer forward de todos os argumentos VAL para o construtor dessa classe ou para a função escolhida (como eu fiz no exemplo acima).

2) Consumir de algum modo os argumentos não-VAL, e chamar recursivamente o mesmo template com os argumentos VAL, de modo que, nessa próxima chamada, uma parte dos argumentos que eram VAL passe a ser não-VAL, encurtando a lista de argumentos, até que ela fique vazia.

3. Re: reticencias e & [RESOLVIDO]

Ricardo Vasconcellos
qxada07

(usa Slackware)

Enviado em 07/08/2017 - 09:08h

Depois da resposta do Paulo imagino que este tópico pode ser alterado para "Resolvido" kkkkk.

Parabéns Paulo.

Att.

Ricardo Vasconcellos
Analista TI Sênior

Jesus Cristo morreu por mim e por você para que tenhamos vida eterna. Jesus Te ama
João 3:16


4. Re: reticencias e & [RESOLVIDO]

Bruno
uNclear

(usa Slackware)

Enviado em 07/08/2017 - 12:01h

qxada07 escreveu:

Depois da resposta do Paulo imagino que este tópico pode ser alterado para "Resolvido" kkkkk.

Parabéns Paulo.


Paulo = monstro em c++


5. Re: reticencias e & [RESOLVIDO]

john kevin de souza
john1710

(usa Ubuntu)

Enviado em 07/08/2017 - 23:52h

Muito obrigado Paulo, me ajudou bastante, agora com base no que me respondestes obtive a compressão necessaria para estudar mais afundo