Karşılaştırma operatörlerini "tuple" ve "tie" aracılığıyla uygulamak, iyi bir fikir mi?


98

(Not: tupleve tieBoost veya C ++ 11'den alınabilir.)
Yalnızca iki öğeli küçük yapılar yazarken std::pair, operator<katı-zayıf sıralama gibi tüm önemli şeyler bu veri türü için zaten yapıldığından, bazen a seçme eğilimindeyim. .
Olumsuz yönleri, oldukça işe yaramaz değişken isimleridir. Kendimi o yarattı bile typedef, ben 2 gün sonra hatırlamayacaksınız firstve hangi secondonlar aynı türden ikisi de, özellikle eğer tam olarak. İkiden fazla üye için bu durum daha da kötüleşiyor, çünkü yuvalama pairoldukça berbat.
Bunun için diğer seçenek birtupleya Boost ya da C ++ 11'den, ancak bu gerçekten daha hoş ve net görünmüyor. Bu yüzden, gerekli karşılaştırma operatörleri de dahil olmak üzere yapıları kendim yazmaya geri dönüyorum.
Özellikle, operator<oldukça külfetli olabileceğinden, sadece aşağıdakiler için tanımlanan işlemlere güvenerek tüm bu karmaşadan kurtulmayı düşündüm tuple:

Örneğin, operator<katı-zayıf-sıralama örneği :

bool operator<(MyStruct const& lhs, MyStruct const& rhs){
  return std::tie(lhs.one_member, lhs.another, lhs.yet_more) <
         std::tie(rhs.one_member, rhs.another, rhs.yet_more);
}

( tieBir hale getirir tupleve T&geçirilen ifade referanslar).


Düzenleme : @DeadMG'den özel olarak miras alma önerisi tuplekötü değil, ancak bazı dezavantajları var:

  • Operatörler bağımsızsa (muhtemelen arkadaş), herkese açık olarak miras almam gerekir
  • Döküm ile, işlevlerim / işleçlerim ( operator=özellikle) kolayca atlanabilir
  • İle tieonlar sipariş için önemli değil eğer çözümü, ben bazı üyelerini bırakabilir

Bu uygulamada dikkate almam gereken herhangi bir sakınca var mı?


1
Bana gayet makul görünüyor ...
ildjarn

1
Sonuç çıkmasa bile bu çok akıllıca bir fikir. Bunu araştırmam gerekecek.
templatetypedef

Bu oldukça makul görünüyor. Şu anda düşünebildiğim tek tuzak tie, bit alanı üyelerine uygulanamayacak olmasıdır.
Ise Wisteria

4
Bu fikri beğendim! Eğer tie(...)çağrılar çeşitli operatörler çoğaltılır olacak (=, ==, <, vs.) Özel bir satır içi yöntem yazabilirsiniz make_tuple(...)o kapsüle ve sonra olduğu gibi, çeşitli diğer yerlerden diyoruz return lhs.make_tuple() < rhs.make_tuple();(gerçi dönüş türünden bu yöntemi açıklamak eğlenceli olabilir!)
aldo

13
@aldo: C ++ 14 kurtarmaya! auto tied() const{ return std::tie(the, members, here); }
Xeo

Yanıtlar:


61

Bu kesinlikle doğru bir işleci yazmayı kendi başınıza döndürmekten daha kolay hale getirecektir. Profil oluşturma, karşılaştırma işleminin uygulamanızın zaman alıcı bir parçası olduğunu gösteriyorsa, yalnızca farklı bir yaklaşımı düşünün derim. Aksi takdirde, bunu sürdürmenin kolaylığı, olası performans endişelerinden daha ağır basmalıdır.


17
Ben dava düşünemiyorum tuple<>s' operator<el yazısıyla olandan daha yavaş olacaktır.
ildjarn

51
Bu aynı fikri bir kez edindim ve bazı deneyler yaptım. Derleyicinin tuple'lar ve referanslarla ilgili her şeyi satır içine aldığını ve optimize ettiğini, montajı elle yazılmış kodla neredeyse aynı şekilde yaydığını görmek beni çok şaşırttı .
JohannesD

7
@JohannesD: Bu ifadeyi destekleyebilirim, bir kez de aynısını yaptım
sehe

Bu kesinlikle zayıf bir siparişi garanti ediyor mu ? Nasıl?
CinCout

5

Aynı problemle karşılaştım ve çözümüm c ++ 11 değişken şablonlarını kullanıyor. İşte kod geliyor:

.H bölümü:

/***
 * Generic lexicographical less than comparator written with variadic templates
 * Usage:
 *   pass a list of arguments with the same type pair-wise, for intance
 *   lexiLessthan(3, 4, true, false, "hello", "world");
 */
bool lexiLessthan();

template<typename T, typename... Args>
bool lexiLessthan(const T &first, const T &second, Args... rest)
{
  if (first != second)
  {
    return first < second;
  }
  else
  {
    return lexiLessthan(rest...);
  }
}

Ve bağımsız değişkenler olmadan temel durum için .cpp:

bool lexiLessthan()
{
  return false;
}

Şimdi örneğiniz şöyle olur:

return lexiLessthan(
    lhs.one_member, rhs.one_member, 
    lhs.another, rhs.another, 
    lhs.yet_more, rhs.yet_more
);

Buraya benzer bir çözüm koydum ama! = Operatörünü gerektirmiyorum. stackoverflow.com/questions/11312448/…
steviekm3

3

Benim fikrime göre, hala std::tupleçözümlerle aynı konuyu ele almıyorsunuz - yani, hem kaç tane hem de her bir üye değişkenin adını bilmelisiniz, bunu işlevde iki kez kopyalıyorsunuz. Kalıtımı tercih edebilirsiniz private.

struct somestruct : private std::tuple<...> {
    T& GetSomeVariable() { ... }
    // etc
};

Bu yaklaşım bir olan küçük biraz daha başlamak için bir karmaşa, ama sadece biri yerine aşırı istediğiniz her operatör için her yerde, tek bir yerde değişkenleri ve isimlerini muhafaza ediyoruz.


3
Yani, T& one_member(){ return std::get<0>(*this); }vb gibi değişkenler için adlandırılmış erişimciler kullanacağım ? Ancak bu benim sahip olduğum her "üye" için, const ve const olmayan sürümler için aşırı yüklemeler de dahil olmak üzere böyle bir yöntem sağlamama gerek yok mu?
Xeo

@Xeo İsimlendirilmiş erişimcilerin gerçek değişkenler oluşturmaktan daha fazla iş gerektirdiğini düşünmüyorum. Her iki durumda da her değişken için ayrı bir isme sahip olmanız gerekir. Sanırım const / non-const için yineleme olacaktır. Ancak, tüm bu çalışmaları şablonlayabilirsiniz.
Lee Louviere

1

Birden fazla operatör aşırı yüklemesi veya tuple'dan daha fazla yöntem kullanmayı planlıyorsanız, tuple'ı sınıfın bir üyesi yapmanızı veya tuple'dan türetmenizi öneririm. Aksi takdirde, yaptığınız şey çok daha fazla iştir. İkisi arasında karar verirken, cevaplanması gereken önemli bir soru şudur: Sınıfınızın bir demet olmasını ister misiniz ? Değilse, bir tuple içermesini ve delegasyon kullanarak arabirimi sınırlandırmanızı tavsiye ederim.

Tuple üyelerini "yeniden adlandırmak" için erişimciler oluşturabilirsiniz.


OP'nin sorusunu "sınıfımı mantıklı operator<kullanarak uygulamak std::tiemı?" Anlamında okudum. Bu cevabın bu soruyla nasıl bir ilgisi olduğunu anlamıyorum.
ildjarn

@ildjarn Burada yayınlamadığım bazı yorumlar var. Her şeyi daha iyi okunması için derledim.
Lee Louviere
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.