Pergunta

Por que ninguém parece usar tuplas em C ++, ou o Impulsione Tuple biblioteca ou a biblioteca padrão para TR1? Eu li um monte de código C ++, e muito raramente posso ver o uso de tuplas, mas muitas vezes eu vejo muitos lugares onde tuplas resolveria muitos problemas (geralmente retorno de vários valores de funções).

Tuples permitir 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 do que este:

temp=a;
a=b;
b=temp;

É claro que você sempre pode fazer isso:

swap(a,b);

Mas o que se pretende rodar três valores? Você pode fazer isso com tuplas:

tie(a,b,c) = make_tuple(b,c,a);

Tuples também torná-lo muito mais fácil para retornar múltipla variável de uma função, que é provavelmente um caso muito mais comum do que trocar valores. Usando referências a valores de retorno certamente não é muito elegante.

Existem grandes desvantagens para tuplas que eu não estou pensando? Se não, por que eles raramente usado? eles são mais lentas? Ou é apenas que as pessoas não estão acostumadas a eles? É uma boa idéia para tuplas de uso?

Foi útil?

Solução

Porque não é ainda standard. Qualquer coisa não-padrão tem um obstáculo muito maior. Pedaços de impulso tornou-se popular porque os programadores estavam pedindo para eles. (Hash_map salta à mente). Mas enquanto tupla é útil, não é uma vitória tão esmagadora e claro que as pessoas se preocupar com isso.

Outras dicas

A resposta cínica é que o programa muitas pessoas em C ++, mas não entendo e / ou utilizar a funcionalidade de nível superior. Às vezes é porque eles não são permitidos, mas muitos simplesmente não tente (ou mesmo entender).

Como um exemplo não-boost: quantas pessoas usam funcionalidade encontrada no <algorithm>

Em outras palavras, muitos programadores C ++ são simplesmente programadores C usando compiladores C ++, e talvez std::vector e std::list. Essa é uma razão pela qual o uso de boost::tuple não é mais comum.

A C ++ tupla sintaxe pode ser um pouco mais detalhado do que a maioria das pessoas gostaria.

Considere o seguinte:

typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;

Então, se você quiser fazer uso extensivo de tuplas que você quer obter typedefs tupla em todos os lugares ou você recebe irritantemente longa digitar nomes em todos os lugares. Eu gosto de tuplas. Eu usá-los quando necessário. Mas é geralmente limitada a um par de situações, como um índice N-elemento ou ao usar multimaps para amarrar os pares gama de iterador. E é geralmente em um escopo muito limitado.

É tudo muito feio e hacky olhando quando comparado a algo como Haskell ou Python. Quando C ++ 0x chegar aqui e temos a 'auto' tuplas palavra-chave começará a olhar muito mais atraente.

A utilidade de tuplas é inversamente proporcional ao número de teclas necessárias para declarar, pack, e descompactá-los.

Para mim, é hábito, as mãos para baixo: Tuples não resolvem nenhum problema novo para mim, apenas alguns que eu já pode lidar muito bem. Trocando valores ainda se sente mais fácil à moda antiga - e, mais importante, eu realmente não penso sobre como trocar "melhor". É bom o suficiente como está.

Pessoalmente, eu não acho que tuplas são uma ótima solução para retornar vários valores -. Soa como um trabalho para structs

Mas e se você quer três valores de rotação?

swap(a,b);
swap(b,c);  // I knew those permutation theory lectures would come in handy.

OK, então com 4 valores etc, eventualmente, o n-tuplo se torna menos código que n-1 permutas. E com default swap isto faz 6 atribuições em vez dos 4 que você teria se você implementou um modelo de três ciclos mesmo, embora eu espero que o compilador iria resolver isso para tipos simples.

Você pode chegar a cenários onde swaps são pesadas ou inapropriado, por exemplo:

tie(a,b,c) = make_tuple(b*c,a*c,a*b);

é um pouco estranho para descompactar.

O ponto é, maneiras, porém, não são conhecidas de lidar com a maioria das situações comuns que tuplas são bons para e, portanto, sem grande urgência para assumir tuplas. Se nada mais, eu não estou confiante de que:

tie(a,b,c) = make_tuple(b,c,a);

não faz 6 cópias, tornando-se totalmente inadequado para alguns tipos (coleções sendo o mais óbvio). Sinta-se livre para me convencer de que tuplas são uma boa idéia para "grandes" tipos, dizendo isso não é assim: -)

Para retornar vários valores, tuplas são perfeitos se os valores são de tipos incompatíveis, mas algumas pessoas não gostam deles se é possível para o chamador para obtê-los na ordem errada. Algumas pessoas não gostam de vários valores de retorno em tudo, e não queremos incentivar a sua utilização, tornando-os mais fácil. Algumas pessoas simplesmente preferem estruturas nomeadas para dentro e para fora parâmetros, e provavelmente não poderia ser persuadido com um taco de beisebol para tuplas de uso. Não respondendo por gosto.

Como muitas pessoas apontaram, tuplas que não são apenas útil como outros recursos.

  1. A troca e truques de rotação são apenas truques. Eles são totalmente confuso para aqueles que não tê-los visto antes, e uma vez que é quase todo mundo, esses truques são apenas más práticas de engenharia de software.

  2. Retornando vários valores usando tuplas é muito menos auto-documentando então as alternativas - retornando tipos nomeados ou usando referências nomeadas. Sem essa auto-documentado, é fácil confundir a ordem dos valores devolvidos, se são mutuamente conversíveis, e não ser mais sábio.

Nem todo mundo pode usar boost, e TR1 não está amplamente disponível ainda.

Ao usar C ++ em sistemas embarcados, puxando em bibliotecas impulso obtem complexa. Eles par ao outro, tamanho de modo biblioteca cresce. Você retorna estruturas de dados ou uso de passagem de parâmetros em vez de tuplas. Ao retornar tuplas em Python a estrutura de dados é da ordem e tipo dos valores devolvidos não apenas a sua explícita.

Você raramente vê-los porque o código bem projetado normalmente não precisa de-los- não há a muitos casos em estado selvagem, onde usando um struct anônimo é superior a usar um chamado. Uma vez que todos uma tupla realmente representa é um struct anônima, a maioria dos codificadores na maioria das situações basta ir com a coisa real.

dizer que temos uma função de "f", onde um retorno tupla pode fazer sentido. Como regra geral, essas funções são normalmente complicado o suficiente para que eles podem falhar.

Se "f" pode falhar, você precisa de um regresso- estado afinal de contas, você não quer que os chamadores tem que inspecionar cada parâmetro para detectar a falha. "F" provavelmente se encaixa no padrão:

struct ReturnInts ( int y,z; }
bool f(int x, ReturnInts& vals);

int x = 0;
ReturnInts vals;
if(!f(x, vals)) {
    ..report error..
    ..error handling/return...
}

Isso não é bonito, mas olhar para o quão feio é a alternativa. Note que eu ainda preciso de um valor de status, mas o código não mais legível e não mais curta é. É provavelmente mais lento também, desde que arcar com os custos de uma cópia com a tupla.

std::tuple<int, int, bool> f(int x);
int x = 0;
std::tuple<int, int, bool> result = f(x); // or "auto result = f(x)"
if(!result.get<2>()) {
    ... report error, error handling ...
}

Outra, desvantagem significativa está escondido em aqui- com "ReturnInts" I pode adicionar alter "f" 's retorno modificando 'ReturnInts' sem alterar 'f'' s INTERFACE. A solução tupla não oferece esse recurso crítico, o que torna a resposta inferior para qualquer código da biblioteca.

Certamente tuplas pode ser útil, mas como mencionado há um pouco de sobrecarga e um obstáculo ou dois você tem que saltar através de antes de poder sequer realmente usá-los.

Se o seu programa encontra consistentemente lugares onde você precisa para retornar vários valores ou de swap vários valores, pode valer a pena ir a rota tupla, mas por outro lado às vezes é apenas mais fácil de fazer as coisas da maneira clássica.

De um modo geral, nem todo mundo já impulso instalado, e eu certamente não iria passar pelo incômodo de baixá-lo e configurar meus incluir diretórios para trabalhar com ele só por suas instalações de tupla. Acho que você vai achar que as pessoas que já utilizam impulso são mais propensos a encontrar usos tupla em seus programas que os usuários não-Boost, e migrantes de outras línguas (Python vem à mente) são mais propensos a ser simplesmente chateado com a falta de tuplas em C ++ do que para explorar métodos de adição de suporte tupla.

Como um std::tuple de dados de loja tem as piores características de ambos um struct e uma matriz; todo o acesso é posição enésima baseado mas não se pode iterar através de um tuple usando um loop for.

Então, se os elementos no tuple são conceitualmente uma série, vou usar um array e se os elementos não são conceitualmente um array, um struct (que nomeou elementos) é mais sustentável. (a.lastname é mais do que explicativo std::get<1>(a)).

Isso deixa a transformação mencionado pelo OP como o usecase única viável para tuplas.

Eu tenho um sentimento que muitos usam Boost.Any e Boost.Variant (com alguma engenharia) em vez de Boost.Tuple.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top