SORU
15 ŞUBAT 2013, Cuma


C 11 std::lambda karşılaştırma işlevi ayarlayın

std::set özel bir karşılaştırma ile bir fonksiyon oluşturmak istiyorum. Elimden tanımlamak gibi bir sınıf ile operator(), ama ben istediğim için zevk yeteneği tanımlamak için bir lambda nerede kullanılır, bu yüzden karar verdim tanımlamak için lambda fonksiyonu başlatma listesi kurucu sınıfı olan std::set gibi bir üye. Ama lambda tipi alamıyorum. Ben devam etmeden önce, burada bir örnek:

class Foo
{
private:
     std::set<int, /*???*/> numbers;
public:
     Foo () : numbers ([](int x, int y)
                       {
                           return x < y;
                       })
     {
     }
};

Arama yaptıktan sonra iki çözüm buldum:, std::function kullanarak. Tam olarak benim yaptığım gibi sadece karşılaştırma işlevi türü std::function<bool (int, int)> ve lambda geçişi var. İkinci çözüm make_set fonksiyon std::make_pair gibi yazmaktır.

ÇÖZÜM 1:

class Foo
{
private:
     std::set<int, std::function<bool (int, int)> numbers;
public:
     Foo () : numbers ([](int x, int y)
                       {
                           return x < y;
                       })
     {
     }
};

ÇÖZÜM 2:

template <class Key, class Compare>
std::set<Key, Compare> make_set (Compare compare)
{
     return std::set<Key, Compare> (compare);
}

Soru bir çözümü tercih etmek için iyi bir nedenim var mı? Standart özellikler (make_set standart bir fonksiyon değildir) kullanır, çünkü ilkini tercih ediyorum, ama merak ediyorum: std::function Bu kod (potansiyel olarak) yavaş olun? kullanarak yapar Demek istediğim düşük şansı derleyici inlines karşılaştırma işlevi, ya da olması gerektiği kadar akıllı uslu aynen eskisi gibi olur bir lambda fonksiyonu yazın ve std::function (biliyorum, bu durumda olamaz lambda tipi, ama biliyorsun, ben soruyorum genel) ?

(GCC kullanıyorum, ama popüler Derleyiciler genel olarak ne olduğunu bilmek istiyorum)

BÜYÜK BİR SÜRÜ CEVAP ALDIM SONRA ÖZETİ:

Eğer hız önemliyse en iyi çözüm operator() aka functor bir sınıf kullanmaktır. Derleyici optimize etmek ve herhangi bir indirections önlemek için çok kolay.

Kolay bakım ve genel amaçlı bir çözüm daha iyi, C 11 özellikleri kullanarak için kullanın std::function. Hala hızlı (biraz eşleme daha yavaş, ama önemsiz de olabilir) ve herhangi bir fonksiyon kullanabilirsiniz std::function, lambda, herhangi bir nesne çağrılabilir.

Ayrıca, bir işlev işaretçisi kullanmak için bir seçenek var, ama eğer hız sorunu varsa yok std::function daha iyi eğer C 11 kullanırsanız () olduğunu düşünüyorum.

Orada bir seçenek tanımlamak için lambda işlevi, başka bir yerde, ama o zaman kazanırsınız yoktan karşılaştırma işlevi olmak bir lambda ifadesi bu yana, mümkün olduğu kadar iyi bir sınıf ile operator() konumu ve tanımı olmaz set inşaat zaten.

Daha fazla fikir, temsilci kullanma gibi. Eğer tüm çözümleri daha detaylı bir açıklama istiyorsanız, cevapları okuyun :)

CEVAP
15 ŞUBAT 2013, Cuma


Evet, bir std::function sizin için neredeyse kaçınılmaz yönlendirme set tanıttı. Süre derleyici her zaman, teorik olarak, anlamaya tüm kullanım setstd::function içerir çağıran bir lambda yani hep aynı lambda, yani her ikisi de zor ve son derece kırılgan.

Kırılgan, çünkü daha önce derleyici kanıtlamak için kendisini tüm aramalar için std::function * aslında bir çağrı için lambda, gerek ispat eden herhangi bir erişim için std::set hiç ayarlar std::function bir şey ama lambda. Tüm derleme birimleri std::set ulaşmak ve hiçbiri bunu kanıtlamak için mümkün olan tüm yolları bulmak demektir.

Bu bazı durumlarda mümkün olabilir, ama nispeten zararsız değişirse derleyici bunu kanıtlamak için yönetilen varsa bile onu kırmak.

Öte yandan, vatansız operator() ile bir functor kolay davranış kanıtlamak zorunda, ve bu iyileştirmeleri içeren günlük şeyler.

Yani Evet, pratikte std::function daha yavaş olabilir şüpheli olurdu. Diğer taraftan, std::function çözüm make_set bir daha korumak için daha kolay ve program performansı için programcı zaman alışverişi oldukça görecelidir.

make_set herhangi bir tür 33**'nın tip 34* *çağrı olayla olmalı. ciddi dezavantajı var Sık sık set depolar kalıcı bir devlet ve oluşturduğunuz bir şey değil o zaman kapsam dışına düşmesine izin yığını.

Eğer oluşturduğunuz bir statik veya global vatansız lambda auto MyComp = [](A const&, A const&)->bool { ... } kullanabilirsiniz std::set<A, decltype(MyComp)> sözdizimi oluşturma set Bu ısrar, henüz kolay derleyici için optimize (çünkü tüm örnekleri decltype(MyComp) vatansız funktorlar) ve satır içi. struct set sokuyorsun çünkü ben, bu işaret etmektedir. (Veya derleyici destekler

struct Foo {
  auto mySet = make_set<int>([](int l, int r){ return l<r; });
};

ben şaşırtıcı bulur!)

Son olarak, eğer sen are endişeli hakkında performans, düşünün std::unordered_set çok daha hızlı (maliyet alamamak için üzerinde yineleme içeriği için, ve yazmak/bulmak iyi karma), ve bir sıralanmış std::vector daha da varsa ve 2-faz "Ekle her şey" sonra "sorgu içeriğini tekrar tekrar". Sadece vector ilk içine şeyler, 46* unique erase*, equal_range ücretsiz algoritması kullanın.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • CommonArtisan

    CommonArtisa

    7 Temmuz 2012
  • Jonah Penna

    Jonah Penna

    11 EYLÜL 2005
  • NYLON Video

    NYLON Video

    11 Aralık 2006