Por que ninguém parece usar tuplas em C ++, nem a Boost Tuple Library ou a biblioteca padrão para TR1? Eu li muito código C ++ e, muito raramente, vejo o uso de tuplas, mas muitas vezes vejo muitos lugares em que as tuplas resolveriam muitos problemas (geralmente retornando vários valores das funções).
As tuplas permitem que você faça todos os tipos de coisas legais como esta:
tie(a,b) = make_tuple(b,a); //swap a and b
Isso é certamente melhor que isso:
temp=a;
a=b;
b=temp;
Claro que você sempre pode fazer isso:
swap(a,b);
Mas e se você quiser girar três valores? Você pode fazer isso com tuplas:
tie(a,b,c) = make_tuple(b,c,a);
As tuplas também facilitam muito o retorno de várias variáveis de uma função, o que provavelmente é um caso muito mais comum do que trocar valores. Usar referências para retornar valores certamente não é muito elegante.
Existem grandes desvantagens nas tuplas em que não estou pensando? Caso contrário, por que eles raramente são usados? Eles são mais lentos? Ou será que as pessoas não estão acostumadas com elas? É uma boa ideia usar tuplas?
a = a ^ b; b = a ^ b; a = a ^ b;
Respostas:
Porque ainda não é padrão. Qualquer coisa fora do padrão tem um obstáculo muito maior. Pedaços de Boost se tornaram populares porque os programadores clamavam por eles. (hash_map vem à mente). Mas enquanto a tupla é útil, não é uma vitória tão esmagadora e clara que as pessoas se preocupam com ela.
fonte
Uma resposta cínica é que muitas pessoas programam em C ++, mas não entendem e / ou usam a funcionalidade de nível superior. Às vezes é porque eles não são permitidos, mas muitos simplesmente não tentam (ou mesmo entendem).
Como um exemplo sem estímulo: quantas pessoas usam a funcionalidade encontrada
<algorithm>
?Em outras palavras, muitos programadores de C ++ são simplesmente programadores de C usando compiladores de C ++, e talvez
std::vector
estd::list
. Essa é uma razão pela qual o uso deboost::tuple
não é mais comum.fonte
A sintaxe da tupla em C ++ pode ser um pouco mais detalhada do que a maioria das pessoas gostaria.
Considerar:
Portanto, se você quiser fazer uso extensivo de tuplas, obtenha typedefs de tupla em todos os lugares ou nomes de tipos irritantemente longos em todos os lugares. Eu gosto de tuplas. Eu os uso quando necessário. Mas geralmente é limitado a algumas situações, como um índice de elemento N ou ao usar multimaps para amarrar os pares de iteradores de intervalo. E é geralmente em um escopo muito limitado.
É tudo muito feio e com aparência de hacker quando comparado a algo como Haskell ou Python. Quando o C ++ 0x chegar aqui e recebermos as tuplas de palavra-chave 'auto', elas parecerão muito mais atraentes.
A utilidade das tuplas é inversamente proporcional ao número de pressionamentos de teclas necessários para declará-los, compactá-los e descompactá-los.
fonte
Para mim, é hábito, mãos para baixo: tuplas não resolvem novos problemas para mim, apenas alguns que eu já consigo lidar bem. A troca de valores ainda parece mais fácil à moda antiga - e, mais importante, eu realmente não penso em como trocar "melhor". É bom o suficiente como está.
Pessoalmente, não acho que as tuplas sejam uma ótima solução para retornar vários valores - parece um trabalho para
struct
s.fonte
Mas e se você quiser girar três valores?
OK, então com 4 valores etc., eventualmente, a n-tupla se torna menos código que n-1 swaps. E com a troca padrão, são 6 atribuições em vez das 4 que você teria se implementasse um modelo de três ciclos, embora eu esperasse que o compilador resolvesse isso para tipos simples.
Você pode criar cenários em que os swaps são pesados ou inapropriados, por exemplo:
é um pouco estranho descompactar.
O ponto é, no entanto, existem maneiras conhecidas de lidar com as situações mais comuns para as quais as tuplas são boas e, portanto, não há grande urgência em aceitar as tuplas. Se nada mais, não estou confiante de que:
não faz 6 cópias, tornando-o totalmente inadequado para alguns tipos (as coleções são as mais óbvias). Fique à vontade para me convencer de que as tuplas são uma boa ideia para tipos "grandes", dizendo que não é assim :-)
Para retornar vários valores, as tuplas são perfeitas se os valores forem de tipos incompatíveis, mas algumas pessoas não gostam deles se for possível para o chamador obtê-las na ordem errada. Algumas pessoas não gostam de vários valores de retorno e não querem incentivar o uso delas, tornando-as mais fáceis. Algumas pessoas simplesmente preferem estruturas nomeadas para parâmetros de entrada e saída e provavelmente não poderiam ser persuadidas com um taco de beisebol a usar tuplas. Não há explicação para o gosto.
fonte
Como muitas pessoas apontaram, as tuplas simplesmente não são tão úteis quanto outros recursos.
Os truques de troca e rotação são apenas truques. Eles são totalmente confusos para aqueles que nunca os viram antes e, como quase todo mundo, esses truques são apenas más práticas de engenharia de software.
Retornar vários valores usando tuplas é muito menos auto-documentado do que as alternativas - retornar tipos nomeados ou usar referências nomeadas. Sem essa auto-documentação, é fácil confundir a ordem dos valores retornados, se eles são mutuamente conversíveis e não são mais sábios.
fonte
Nem todo mundo pode usar o impulso, e o TR1 ainda não está amplamente disponível.
fonte
Ao usar o C ++ em sistemas incorporados, a atração das bibliotecas do Boost fica complexa. Eles se juntam, então o tamanho da biblioteca aumenta. Você retorna estruturas de dados ou usa a passagem de parâmetros em vez de tuplas. Ao retornar tuplas em Python, a estrutura de dados está na ordem e no tipo dos valores retornados, mas isso não é explícito.
fonte
Você raramente os vê porque o código bem projetado geralmente não precisa deles - não existem muitos casos em que o uso de uma estrutura anônima é superior ao uso de uma nomeada. Como tudo que uma tupla realmente representa é uma estrutura anônima, a maioria dos codificadores, na maioria das situações, apenas acompanha a coisa real.
Digamos que temos uma função "f" em que um retorno da tupla pode fazer sentido. Como regra geral, essas funções geralmente são complicadas o suficiente para que possam falhar.
Se "f" PODE falhar, você precisará retornar um status; afinal, você não quer que os chamadores tenham que inspecionar todos os parâmetros para detectar falhas. "f" provavelmente se encaixa no padrão:
Isso não é bonito, mas veja como a alternativa é feia. Observe que ainda preciso de um valor de status, mas o código não é mais legível e nem mais curto. Provavelmente também é mais lento, pois incorre no custo de 1 cópia com a tupla.
Outra desvantagem significativa está oculta aqui - com "ReturnInts", posso adicionar o retorno de alter "f" modificando "ReturnInts" SEM ALTERAR A INTERFACE de "f". A solução de tupla não oferece esse recurso crítico, o que a torna a resposta inferior para qualquer código de biblioteca.
fonte
using std::tuple;
e apenas usandotuple
o código.tuple
torna o código menos legível, não mais. Atualmente, a maioria dos códigos possui um número muito grande de símbolos - a visãostd::tuple
deixa claro aos olhos exatamente o que é.Certamente, as tuplas podem ser úteis, mas, como mencionado, há um pouco de sobrecarga e uma ou duas barreiras que você precisa passar antes que possa usá-las.
Se o seu programa encontrar consistentemente locais onde você precisa retornar vários valores ou trocar vários valores, pode valer a pena seguir a rota da tupla, mas, caso contrário, às vezes é apenas mais fácil fazer as coisas da maneira clássica.
De um modo geral, nem todo mundo já possui o Boost instalado, e eu certamente não passaria pelo trabalho de fazer o download e configurar meus diretórios de inclusão para trabalhar com ele apenas por suas instalações de tupla. Acho que você descobrirá que as pessoas que já usam o Boost têm maior probabilidade de encontrar usos de tupla em seus programas do que os usuários que não são do Boost, e os migrantes de outros idiomas (Python vem à mente) têm mais probabilidade de simplesmente ficarem chateados com a falta de tuplas em C ++ do que explorar métodos para adicionar suporte à tupla.
fonte
Como um armazenamento de dados
std::tuple
tem as piores características de umstruct
e um array; todo o acesso é a enésima posição, mas não se pode iterartuple
usando umfor
loop.Portanto, se os elementos no
tuple
são conceitualmente uma matriz, usarei uma matriz e se os elementos não forem conceitualmente uma matriz, uma estrutura (que nomeou elementos) é mais sustentável. (a.lastname
é mais explicativo do questd::get<1>(a)
).Isso deixa a transformação mencionada pelo OP como a única via viável para tuplas.
fonte
Sinto que muitos usam Boost.Any e Boost.Variant (com alguma engenharia) em vez do Boost.Tuple.
fonte