C ++ 'da tuple kullanımı neden daha yaygın değil?


124

Neden hiç kimse C ++ 'da, Boost Tuple Kitaplığı veya TR1 için standart kitaplık kullanmıyor gibi görünüyor ? Çok fazla C ++ kodu okudum ve çok nadiren tuple kullanımını görüyorum, ancak çoğu zaman tupleların birçok sorunu çözebileceği birçok yer görüyorum (genellikle işlevlerden birden çok değer döndürür).

Tuples, bunun gibi her türlü harika şeyi yapmanıza izin verir:

tie(a,b) = make_tuple(b,a); //swap a and b

Bu kesinlikle bundan daha iyi:

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

Tabii ki bunu her zaman yapabilirsiniz:

swap(a,b);

Peki ya üç değeri döndürmek isterseniz? Bunu tuple ile yapabilirsiniz:

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

Tuples ayrıca, bir işlevden birden çok değişkeni döndürmeyi çok daha kolaylaştırır, bu muhtemelen değerleri değiştirmekten çok daha yaygın bir durumdur. Değerleri döndürmek için referans kullanmak kesinlikle çok şık değil.

Tuple'ların benim düşünmediğim büyük dezavantajları var mı? Değilse, neden nadiren kullanılıyorlar? Daha yavaşlar mı? Yoksa sadece insanlar onlara alışkın değil mi? Tuple kullanmak iyi bir fikir mi?


17
Akıllı tuple takas numarası için +1 :)
kizzx2

10
a = a ^ b; b = a ^ b; a = a ^ b;
Gerardo MARSET

3
IMO dizileri, zayıf yazım dillerinde veya yerel yapılar oldukları dillerde kullanışlıdır. Örneğin Python veya PHP'de hayatı kolaylaştırırlar, C ++ 'da ise çok fazla yazım (şablondan oluşturmak için) ve çok az fayda vardır.
doktor

4
OP'ye bir yorum: Mevcut kabul edilmiş cevabın, gerçeklere dayalı olarak yanlış olma noktasına kadar zaten geçersiz olduğunu düşünüyorum. Kabul edilen cevabın seçimini yeniden gözden geçirmek isteyebilirsiniz.
ulidtko

8
@GerardoMarset Ciddi misin?
thesaint

Yanıtlar:


43

Çünkü henüz standart değil. Standart olmayan herhangi bir şeyin çok daha büyük bir engeli vardır. Boost Parçaları, programcılar onlara haykırdığı için popüler hale geldi. (hash_map akla gelir). Ancak tuple kullanışlı olsa da, insanların ondan rahatsız olacağı kadar büyük ve net bir kazanç değil.


1
İnsanlar Boost'un diğer bölümlerini deli gibi kullanıyor gibi görünüyor. Kesinlikle karma haritalar genel olarak tuple'lardan çok daha kullanışlıdır.
Zifre

Gördüğünüz şeyin ayrıntılarını bilmiyorum ama sanırım insanların çılgınlar gibi kullandıkları parçalar gerçekten, gerçekten istedikleri özellikler. Böylece (yine, tahmin ederek) hash haritasının, sayılan işaretçinin ve benzerlerinin popülaritesi. Tuple kullanışlıdır, ancak bir deliği doldurmak için dışarı fırlayan bir şey değildir. Getirisi açık değil. Tam olarak N nesneyi ne sıklıkla döndürmeniz gerekiyor? (Rasgele uzun vektörleri döndürme ihtiyacının aksine). Ve insanlar, dönüş değerlerini referans olarak iletmeye veya küçük sınıflar veya yapılar döndürmeye alışkındır.
Alan De Smet

20
Aslında şu anda C ++ 11 standardının bir parçası: en.cppreference.com/w/cpp/utility/tuple
Roman Susi

124

Alaycı bir cevap, birçok kişinin C ++ 'da programladığı, ancak daha yüksek seviye işlevselliği anlamadığı ve / veya kullanmadığıdır. Bazen bunun nedeni onlara izin verilmemesidir, ancak çoğu sadece denemiyor (hatta anlamıyor).

Takviye içermeyen bir örnek olarak: içinde bulunan işlevleri kaç kişi kullanıyor <algorithm>?

Başka bir deyişle, birçok C ++ programcısı, C ++ derleyicilerini kullanan C programcılarıdır ve belki std::vectorve std::list. Kullanımının boost::tupledaha yaygın olmamasının bir nedeni budur .


18
-1 benden çünkü C ++ programcıları bu cevap onlara kulağa hoş geldiği kadar aptal değil.
user541686

5
@Mehrdad Hem ticari hem de değil, çok sayıda C ++ koduna baktıktan sonra, tonlarca C ++ materyali okuduktan sonra, "C ++" geliştiricilerinin çok büyük bir kısmının, saf bir C geliştiricisi olduğunu söylemenin oldukça güvenli olduğunu düşünüyorum. C derleyicisi. Örneğin şablonlar çoğu materyalde neredeyse tamamen eksiktir (çok sevmeyi öğrendiğim bir şey). Garip makro saldırıları yaygındır ve ad alanı çok az kullanılır.
Daha net

5
Saçma cevap. Eğer biri onlara ihtiyaç duyarsa, onlara yetişeceklerdir. Bunlara ihtiyaç yoktur; bu yüzden kullanılmazlar. Kolay anlaşılamadığı için kullanılmadığını söylemek kötüdür.
Michael Chourdakis

9
@Michael Saçma yorum. Bir dilin Turing tam alt kümesine sahip olduğunuzda programlamada hiçbir şeye gerek yoktur . Kullanım eksikliği kesinlikle herkesin daha yüksek seviyeli C ++ yapılarını anladığı ve bunları kullanmamayı seçtiği anlamına gelmez.
Trey Jackson

4
Tbh Ben ASLA variadik şablon metaprogramlama dışında std :: tuple'a ihtiyacım olmadı. Hayatta üzgün bir suratla oturup "Keşke o tuplelerse" diye düşünmenin hiçbir anlamı yoktu. Aslında demetlere baktığımda "Aklı başında biri onlara neye ihtiyaç duyar ki (kendimi aklı başında saymazdım)" diye düşünüyorum. Meta-programlamanın dışındaki insanlar, onları çok çirkin olan ve kafalarında kod kalitesinin ve sürdürülebilirliğin güçlü olmadığını gösteren "Anonim Yapı" olarak kullanıyor gibi görünüyor.
thesaint

23

C ++ tuple sözdizimi çoğu insanın istediğinden biraz daha ayrıntılı olabilir.

Düşünmek:

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

Öyleyse, tuple'ları kapsamlı bir şekilde kullanmak istiyorsanız, ya her yerde tuple typedef'leri alırsınız ya da her yerde can sıkıcı derecede uzun tip isimler alırsınız. Demetleri severim. Gerektiğinde kullanıyorum. Ancak, genellikle bir N-öğe dizini gibi birkaç durumla veya aralık yineleyici çiftlerini bağlamak için çoklu haritalar kullanıldığında sınırlıdır. Ve genellikle çok sınırlı bir kapsamdadır.

Haskell veya Python gibi bir şeye kıyasla hepsi çok çirkin ve huysuz görünüyor. C ++ 0x buraya geldiğinde ve 'auto' anahtar kelimesini aldığımızda, çok daha çekici görünmeye başlayacak.

Tuple'ların kullanışlılığı, bunları bildirmek, paketlemek ve paketten çıkarmak için gereken tuş vuruşlarının sayısı ile ters orantılıdır.


Çoğu kişi "ad alanı artırma kullanarak" yapacak; ve boost :: yazmanız gerekmez. Tuple yazmanın o kadar da sorun olduğunu sanmıyorum. Bununla birlikte, haklı olduğunu düşünüyorum. auto, daha fazla insanın tuple kullanmaya başlamasını sağlayabilir.
Zifre

2
@Zifre: Sorun şu ki, başlık dosyası içinde "X ad alanını" kullanmamalısınız çünkü bu ad alanı kirliliğini zorlar ve ad alanlarını alt üst eder.
Bay Fooz

1
Ah, evet, başlıkları unuttum. Ancak program kodunun içinde bunun için endişelenmenize gerek yok. Ve bir kez C ++ 0x'e sahip olduğumuzda, birçok yazmayı ortadan kaldırması gereken otomatik'i kullanabiliriz.
Zifre

19
Sadece ben mi? Onun kastettiği şeyin "boost ::" 'un 7 karakterini yazmaktan tasarruf ettiğini düşünmüyorum, daha ziyade diğer 33 karakter . Bu, özellikle de ad alanı kapsamına alınmışsa, çok fazla sınıf adı yazma işi demektir. Komik bir örnek olarak boost :: tuple <std :: string, std :: set <std :: string>, std :: vector <My :: Scoped :: LongishTypeName>> alın.
Ogre Mezmuru33

10

Benim için bu alışkanlık, eller aşağı: Tuples benim için yeni problemleri çözmüyor, sadece birkaçını zaten halledebilirim. Değerleri değiş tokuş etmek hala eski usulden daha kolay geliyor - ve daha da önemlisi, nasıl "daha iyi" değiştirileceğini gerçekten düşünmüyorum. Olduğu gibi yeterince iyi.

Kişisel olarak, tupleların birden çok değeri döndürmek için harika bir çözüm olduğunu düşünmüyorum - kulağa structs için bir iş gibi geliyor .


4
"Nasıl" daha iyi "takas edeceğimi gerçekten düşünmüyorum. '- Kod yazarken, hatalar yazarım. Kod karmaşıklığını azaltmak, yazdığım hataların sayısını azaltır. Aynı böcekleri tekrar tekrar yaratmaktan nefret ediyorum. Evet, kodu nasıl daha iyi <strike> değiştirebileceğimi </> düşünüyorum . Daha az hareketli parça (LOC, geçici değişkenler, yanlış yazılacak tanımlayıcılar), daha okunabilir kod; İyi Kod.
sehe

Katılıyorum. Otomatik işaretçi veya akıllı işaretçi ile sarılmış bir sınıf, tür kaydetmedir. Bir kez tuple kullandım, ancak daha sonra sınıfları kullanarak kodu yeniden yazdım. retValue.state, retValue.get <0> () 'den daha açıktır.
Valentin Heinitz

1
@sehe: Daha iyi, daha okunaklı kod yazmak benim de hedefim. Daha fazla sözdizimi türü eklemenin bir maliyeti vardır ve "daha iyi değiş tokuş etmenin" okuduğunuz her kod satırı için daha fazla sözdizimi türü düşünmenin zihinsel yükünü haklı çıkardığına inanmıyorum.
ojrac

8

Peki ya üç değeri döndürmek isterseniz?

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

Tamam, 4 vb. Değerlerde, sonunda n-tuple n-1 takaslardan daha az kod olur. Ve varsayılan takas ile bu, üç döngülü bir şablonu kendiniz uyguladıysanız sahip olacağınız 4 yerine 6 atama yapar, ancak derleyicinin bunu basit türler için çözeceğini umuyorum.

Takas işlemlerinin hantal veya uygunsuz olduğu senaryolar üretebilirsiniz, örneğin:

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

paketini açmak biraz garip.

Mesele şu ki, tupleların iyi olduğu en yaygın durumlarla başa çıkmanın bilinen yolları vardır ve bu nedenle tuple'ları almak için büyük bir aciliyet yoktur. Hiçbir şey değilse, bundan emin değilim:

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

6 kopya yapmaz, bu da bazı türler için tamamen uygunsuz hale getirir (koleksiyonlar en bariz olanıdır). Bunun öyle olmadığını söyleyerek demetlerin "büyük" türler için iyi bir fikir olduğuna beni ikna etmekten çekinmeyin :-)

Birden çok değer döndürmek için, değerler uyumsuz türdeyse, demetler mükemmeldir, ancak arayanın bunları yanlış sırada alması mümkünse, bazı kişiler bunlardan hoşlanmaz. Bazı insanlar birden fazla dönüş değerini hiç sevmez ve onları daha kolay hale getirerek kullanımlarını teşvik etmek istemezler. Bazı insanlar sadece giriş ve çıkış parametreleri için adlandırılmış yapıları tercih ederler ve muhtemelen bir beyzbol sopası ile tuple kullanmaya ikna edilemezler. Zevk için hesap yok.


1
Vektörleri tuple ile değiştirmek kesinlikle istemezsiniz. Bence üç elementi değiş tokuş etmenin iki değiş tokuştan çok tuple ile kesinlikle daha net olduğunu düşünüyorum. Birden çok dönüş değerine gelince, çıkış parametreleri kötüdür, yapılar fazladan yazmadır ve kesinlikle birden çok dönüş değerinin gerekli olduğu durumlar vardır.
Zifre

Neden biliyor sen dizilerini kullanmak (ve vesilesiyle ortaya çıktığında ben hiç sanmıyorum rağmen, bunları kullanmak istiyorum neden biliyorum). Başkalarının farkında olsalar bile neden kullanmadığını tahmin ediyorum. örneğin "paramlar kötüdür" fikrine katılmadıkları için ...
Steve Jessop

"Tie (a, b, c) = make_tuple (b, c, a);" yerine geçip geçemeyeceğimizi biliyor musunuz? "bağ (a, b, c) = bağ (b, c, a);" ?
Rexxar

2
Bir bağ (iyi, teknik olarak bir katman) const olmayan referanslarla yapılan bir demettir. Operatör = neyin garanti edildiğini ve ilgili referanslardan bazılarının aynı referansa sahip olması durumunda bağlantı / tuple için kopya yapıcının yaptığını belirten destek belgelerini bulamıyorum. Ama bilmen gereken bu. Operatörün saf bir uygulaması = açıkça çok yanlış gidebilir ...
Steve Jessop

1
@Steve: Ve bağları kopya önleme hakkında tüm çünkü aslında genel olarak tüm (onlar olmayan copyable türleri için çalışmalıdır LHS tamamen başka bir şey olabilir o notu) olmalıdır (POD olmayan sınıf nesneleri düşünün) çok yanlış. Geçici kullanmadan aynı mantığı nasıl yazacağınızı hayal edin.
sehe

7

Pek çok kişinin işaret ettiği gibi, tuplelar diğer özellikler kadar kullanışlı değildir.

  1. Takas etme ve döndürme hileleri sadece hiledir. Onları daha önce görmemiş olanlar için tamamen kafa karıştırıcıdırlar ve hemen hemen herkes olduğu için, bu hileler sadece kötü yazılım mühendisliği uygulamalarıdır.

  2. Tuples kullanarak birden çok değer döndürmek, kendi kendini belgelemekten çok daha az alternatiftir - adlandırılmış türleri döndürmek veya adlandırılmış referansları kullanmak. Bu kendini belgeleme olmadan, eğer karşılıklı olarak dönüştürülebilirlerse ve daha akıllıca değilse, döndürülen değerlerin sırasını karıştırmak kolaydır.


6

Herkes boost kullanamaz ve TR1 henüz yaygın olarak kullanılamaz.


3
Pek çok insan Boost kullanıyor. Bu insanlar da tuple kullanıyor olabilir.
Zifre

3
İnsanların neden kullanmadığını sordun ve ben bir cevap verdim.
Brian Neal

2
Aşağı seçmen için: Güçlendirme kullanmanın siyasi olarak imkansız olduğu bir yerde çalışıyorum ve bu tarihte bile kullandığımız derleyici araç zinciri (gömülü bir sistem için) TR1 / C ++ 11 desteğine sahip değil.
Brian Neal

5

Gömülü sistemlerde C ++ kullanırken, Boost kitaplıklarını çekmek karmaşıklaşır. Birbirleriyle çiftleşirler, böylece kitaplık boyutu büyür. Veri yapılarını döndürürsünüz veya tuple yerine parametre geçişini kullanırsınız. Python'da tuplelar döndürüldüğünde, veri yapısı döndürülen değerlerin sırası ve türündedir, açık değildir.


5

Onları nadiren görürsünüz çünkü iyi tasarlanmış kod genellikle onlara ihtiyaç duymaz - vahşi ortamda anonim bir yapı kullanmanın adlandırılmış bir yapıdan daha üstün olduğu pek çok durumda yoktur. Bir demetin temsil ettiği her şey anonim bir yapı olduğundan, çoğu durumda çoğu kodlayıcı sadece gerçek olanı kullanır.

Bir demet dönüşünün anlamlı olabileceği bir "f" fonksiyonumuz olduğunu varsayalım. Genel bir kural olarak, bu tür işlevler genellikle başarısız olabilecek kadar karmaşıktır.

"F" CAN başarısız olursa, bir durum geri dönüşüne ihtiyacınız vardır - sonuçta, arayanların arızayı tespit etmek için her parametreyi incelemek zorunda kalmasını istemezsiniz. "f" muhtemelen kalıba uyuyor:

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...
}

Bu hoş değil ama alternatifin ne kadar çirkin olduğuna bakın. Yine de bir durum değerine ihtiyacım olduğunu, ancak kodun artık okunabilir olmadığını ve daha kısa olmadığını unutmayın. Tuple ile 1 kopya maliyetine maruz kaldığım için muhtemelen daha yavaştır.

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 ...
}

Bir başka önemli dezavantajı burada gizli - "ReturnInts" ile "f" nin ARAYÜZÜNÜ DEĞİŞTİRMEDEN "ReturnInts" i değiştirerek "f" nin dönüşünü değiştirebilirim. Tuple çözümü bu kritik özelliği sunmuyor, bu da onu herhangi bir kütüphane kodu için daha düşük cevap yapıyor.


1
İstisnalar bu arayüzü çok daha temiz hale getirir.
David Stone

Adil olmak gerekirse (ve partiye son derece geç), okunabilirliği ayarlayarak using std::tuple;ve sadece tuplekodu kullanarak kolaylaştırabilirsiniz .
Alrekr

2
Kullanmak tuple, kodu daha fazla değil, daha az okunabilir hale getirir . Bugünlerde çoğu kodda çok sayıda sembol var - görmek std::tuple, tam olarak ne olduğunu göze açık hale getiriyor.
Tom Swirly

3

Kesinlikle tuples yararlı olabilir, ancak belirtildiği gibi, onları gerçekten kullanmadan önce atlamanız gereken bir miktar ek yük ve bir veya iki engel vardır.

Programınız sürekli olarak birden çok değer döndürmeniz veya birkaç değeri takas etmeniz gereken yerleri bulursa, tuple rotasına gitmeye değer olabilir, ancak bazen işleri klasik yoldan yapmak daha kolaydır.

Genel olarak konuşursak, herkesin Boost'u zaten kurulu değil ve kesinlikle onu indirme ve dahil dizinlerimi sadece tuple tesisleri için onunla çalışacak şekilde yapılandırma zahmetine girmem. Zaten Boost'u kullananların, programlarında Boost kullanmayanlara göre tuple kullanımları bulma olasılıklarının daha yüksek olduğunu ve diğer dillerden gelen göçmenlerin (Python akla geliyor) demetlerin eksikliğinden daha fazla üzüldüğünü göreceksiniz. C ++ 'da tuple desteği ekleme yöntemlerini keşfetmekten çok.


1

Bir veri deposu std::tuplehem a hem de structdizinin en kötü özelliklerine sahip olduğundan ; tüm erişim n'inci konuma dayalıdır, ancak tuplebir fordöngü kullanarak yineleme yapılamaz .

Yani eğer içindeki elemanlar tuplekavramsal olarak bir dizi ise, bir dizi kullanacağım ve elemanlar kavramsal olarak bir dizi değilse, bir yapı (elemanları adlandırılmış olan) daha sürdürülebilirdir. ( a.lastnamedaha açıklayıcıdır std::get<1>(a)).

Bu, OP tarafından belirtilen dönüşümü tuple'lar için geçerli tek kullanım alanı olarak bırakır.


0

Birçoğunun Boost.Tuple yerine Boost.Any ve Boost.Variant'ı (biraz mühendislik ile) kullandığını hissediyorum.


Neden böyle bir şey için verimli statik yazmayı takas edesiniz?
Zifre

Boost.Variant tamamen tür açısından güvenlidir.
user21714

1
Oops, evet bu tür güvenlidir, ancak çalışma zamanı yazımı yapar.
Zifre

5
Tuple'ın Any / Variant ile nasıl değiştirilebileceğini anlamıyorum. Aynı şeyi yapmazlar.
Mankarse

1
@Zifre Yazar adına konuşamam, ama bence buradaki çıkarım onları diğer konteyner türleriyle birlikte kullanmaktır.
Tim Seguine
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.