Hangi C ++ Standart Kitaplık sarmalayıcı işlevlerini kullanıyorsunuz?


81

Bu sabah sorulan bu soru , C ++ Standart Kitaplığı'nda eksik olduğunu düşündüğünüz özelliklerin neler olduğunu ve boşlukları sarmalayıcı işlevleriyle nasıl doldurduğunuzu merak etmeme neden oldu. Örneğin, kendi yardımcı kitaplığım vektör ekleme için şu işleve sahiptir:

template <class T>
std::vector<T> & operator += ( std::vector<T> & v1,
                               const std::vector <T> & v2 ) {
    v1.insert( v1.end(), v2.begin(), v2.end() );
    return v1;
}

ve bu, herhangi bir türü temizlemek için (aşağı yukarı) - özellikle std :: stack gibi şeyler için kullanışlıdır:

template <class C>
void Clear( C & c ) {
    c = C();
}

Birkaç tane daha var ama hangilerini kullandığınla ilgileniyorum? Lütfen sarmalayıcı işlevlerine yanıtları sınırlandırın - yani birkaç satır koddan fazla olamaz.


9
STL algoritmasının çoğunu aralıklar yerine tüm kapsayıcılar üzerinde hareket edecek şekilde sardığım sayılır mı, çünkü yineleyicilerle uğraşmak çok yaygın bir hata :)?
Matthieu M.

2
@Billy aslında, CW öznel sorular sormak için bir bahane değil. İnsanları mutlu edecek başlığı değiştireceğim.

4
@kts: vector :: insert'e rastgele erişim yineleyiciler verildiğinden, iyi bir uygulama bunu kendisi yapmak için derleme zamanı gönderimini kullanacaktır.

4
c.swap(C())Bir konteyneri temizlemek için yazmak daha iyi değil mi?
Alexandre C.

5
@Alexandre: Buna izin verilmez: sabit olmayan bir referansa bir geçici bağlar. C (). Takas (c) işe yarar.

Yanıtlar:


37

boost :: dizi

içerir (kapsayıcı, val) (oldukça basit, ancak kullanışlı).

template<typename C, typename T>
bool contains(const C& container, const T& val) {
   return std::find(std::begin(container), std::end(container), val) != std::end(container);
}

remove_unstable (başlangıç, bitiş, değer)

Kalan nesnelerin sırasını korumaması dışında std :: remove'in daha hızlı bir versiyonu.

template <typename T> 
T remove_unstable(T start, T stop, const typename T::value_type& val){  
    while(start != stop) {      
        if (*start == val) {            
            --stop;             
            ::std::iter_swap(start, stop);      
        } else {            
            ++start;        
        }   
    }   
    return stop; 
}

(pod türleri vektörünün (int, float vb.) ve neredeyse tüm nesnelerin kaldırılması durumunda, std :: remove daha hızlı olabilir).


4
Başkasının bu yeterli yeri üçüncü bir şablon (içerir düşünüyor mu bool sorted=false) ve bir uzmanlık sorted==truearamaya binary_searchyerine find?
KitsuneYMG

6
@kts: Konteynerin sıralandığını bildiğiniz zaman , doğrudan binary_search çağırın .

2
boost :: array STL eşdeğeri, en son derleyicilerde tr1 ad alanında mevcuttur (hatta kod savaşçısı): std :: tr1 :: array <>
Klaim

36

Çoğu zaman vektörü belirli bir sıraya göre olmayan bir dizi öğe olarak kullanırdım (ve tabii ki, hızlı bir şekilde bu set-içindeki-öğe kontrollerine ihtiyacım olmadığında) Bu gibi durumlarda, silme () işlevini çağırmak zaman kaybıdır çünkü öğeleri yeniden sıralayacaktır ve düzeni umursamıyorum. İşte o zaman aşağıdaki O (1) işlevi işe yarar - sadece son öğeyi silmek istediğinizin konumuna getirin:

template<typename T>
void erase_unordered(std::vector<T>& v, size_t index)
{
    v[index] = v.back();
    v.pop_back();
}

İyi bir. Böyle yapmayı düşünmemiştim .. :) Sipariş önemli olmadığında bu operasyonları hızlandıran (istif ve sıraya benzer) bir 'Çanta' sargısı olmalı.
Macke

12
Ve C ++ 0x'de, v[index] = st::move(v.back()); v.pop_back();olabildiğince verimlidir.
GManNickG

@Matthieu: Bunların üzerindeki zaman damgasına bakın. : PI, izin verilen düzenleme süresinin çok ötesinde birkaç saat sonra fark etti.
GManNickG

@GMan: Bundan emin misin? bana, yıkıcı çağrılacağı için v.pop_back () tanımsız davranışla sonuçlanabilir gibi görünüyor.
Viktor Sehr

1
@Viktor: Move semantiği "Kaynaklarını alıyorum ve bu" demek değil, "Kaynaklarını alıyorum ve seni kaynaksız bir duruma sokuyorum" demek. Başka bir deyişle, hareket semantiğinizin nesnenin güvenli bir şekilde yok edebileceğinden emin olması gerekir; yapmak oldukça kolay, sadece işaretçileri null olarak ayarlayın.
GManNickG

26
template < class T >
class temp_value {
    public :
        temp_value(T& var) : _var(var), _original(var) {}
        ~temp_value()        { _var = _original; }
    private :
        T&  _var;
        T   _original;
        temp_value(const temp_value&);
        temp_value& operator=(const temp_value&);
};

Bu kadar düz ileri düşündüğüm gibi değil gibi görünüyor çünkü Tamam, burada açıklamaları aşağıda bulabilirsiniz:
onun yapıcı olarak temp_valuemağazalarda bir değişkenin başvurusu ve değişkenin orijinal değerinin bir kopyası. Yıkıcıda, başvurulan değişkeni orijinal değerine geri yükler. Yani, inşa ve yıkım arasındaki değişkene ne yaparsanız yapın, temp_valuenesne kapsam dışına çıktığında sıfırlanacaktır .
Bunu şu şekilde kullanın:

void f(some_type& var)
{
  temp_value<some_type> restorer(var); // remembers var's value

  // change var as you like
  g(var);

  // upon destruction restorer will restore var to its original value
}

İşte kapsam koruma hilesini kullanan başka bir yaklaşım:

namespace detail
{
    // use scope-guard trick
    class restorer_base
    {
    public:
        // call to flag the value shouldn't
        // be restored at destruction
        void dismiss(void) const
        {
            mDismissed = true;
        }

    protected:
        // creation
        restorer_base(void) :
        mDismissed(false) 
        {}

        restorer_base(const restorer_base& pOther) :
        mDismissed(pOther.is_dismissed())
        {
            // take "ownership"
            pOther.dismiss();
        }

        ~restorer_base(void) {} // non-virtual

        // query
        bool is_dismissed(void) const
        {
            return mDismissed;
        }

    private:
        // not copy-assignable, copy-constructibility is ok
        restorer_base& operator=(const restorer_base&);

        mutable bool mDismissed;
    };

    // generic single-value restorer, could be made 
    // variadic to store and restore several variables
    template <typename T>
    class restorer_holder : public restorer_base
    {
    public:
        restorer_holder(T& pX) :
        mX(pX),
        mValue(pX)
        {}

        ~restorer_holder(void)
        {
            if (!is_dismissed())
                mX = mValue;
        }

    private:
        // not copy-assignable, copy-constructibility is ok
        restorer_holder& operator=(const restorer_holder&);

        T& mX;
        T mValue;
    };
}

// store references to generated holders
typedef const detail::restorer_base& restorer;

// generator (could also be made variadic)
template <typename T>
detail::restorer_holder<T> store(T& pX)
{
    return detail::restorer_holder<T>(pX);
}

Bu sadece biraz daha fazla kazan plakası kodudur, ancak daha temiz bir kullanıma izin verir:

#include <iostream>

template <typename T>
void print(const T& pX)
{
    std::cout << pX << std::endl;
}

void foo(void)
{
    double d = 10.0;
    double e = 12.0;
    print(d); print(e);

    {
        restorer f = store(d);
        restorer g = store(e);

        d = -5.0;
        e = 3.1337;
        print(d); print(e);

        g.dismiss();
    }

    print(d); print(e);
}

int main(void)
{
    foo();

    int i = 5;
    print(i);

    {
        restorer r = store(i);

        i *= 123;
        print(i);
    }

    print(i);
}

Yine de bir sınıfta kullanılma yeteneğini ortadan kaldırır.


İşte aynı etkiyi elde etmenin üçüncü bir yolu (potansiyel olarak yıkıcı fırlatma sorunlarından etkilenmez):

Uygulama:

//none -- it is built into the language

Kullanım:

#include <iostream>

template <typename T>
void print(const T& pX)
{
    std::cout << pX << std::endl;
}

void foo(void)
{
    double d = 10.0;
    double e = 12.0;
    print(d); print(e);

    {
        double f(d);
        double g(e);

        f = -5.0;
        g = 3.1337;
        print(f); print(g);

        e = std::move(g);
    }

    print(d); print(e);
}

int main(void)
{
    foo();

    int i = 5;
    print(i);

    {
        int r(i);

        r *= 123;
        print(r);
    }

    print(i);
}

1
@Billy: Değeri daha sonra otomatik olarak geri yüklemek için. (Ve val ctordan çıkarılmalıdır.)

Üzgünüm, hala kayboldum (C ++ 'da yeniyim), herhangi biri bunu aptal yerine koyabilir mi?
dreamlax

1
@dreamlax: Cevaba açıklayıcı bir metin ekledim. Şimdi anlaşılabilir mi yoksa ayrıntılara daha derin mi inmeliyim?
sbi

1
oh, ikincisi oldukça zekice.
jalf

1
Hmm bunun için gerçek hayattaki kullanım durumu nedir?
paulm

22

Gerçek bir paket değil, rezil bir eksik copy_if. Gönderen burada

template<typename In, typename Out, typename Pred>
Out copy_if(In first, In last, Out res, Pred Pr)
{
    while (first != last) {
        if (Pr(*first)) {
            *res++ = *first;
        }
        ++first;
    }
    return res;
}

2
Soruya cevap vermiyor, stdlib için bir paketleyici değil.

10
@Roger Pate, evet biliyorum, bu yüzden cevap "Gerçekten bir paketleyici değil, ama ...." sözleriyle başlıyor.
Glen

1
@Roger uygulama detayı. Gerçekten dilerseniz bunu anlamında uygulayabilirsiniz remove_copy_if(). : p
wilhelmtell

18
template< typename T, std::size_t sz >
inline T* begin(T (&array)[sz]) {return array;}

template< typename T, std::size_t sz >
inline T* end  (T (&array)[sz]) {return array + sz;}

2
Bende de var. :) +1 Değeri ne olursa olsun, sadece ikisine ihtiyacınız var (const sürümlerinden kurtulun). Dizi sabit olduğunda, Tolacaktır const Uve amaçlanan işlevi elde edersiniz.
GManNickG

@GMan: Bazı kodları sadece constversiyon olmayanlarla derlemeyen bir GCC versiyonu vardı, bu yüzden constversiyonlar var. Bu, belirli GCC sürümünün bir hatası olabileceğinden, onları kaldıracağım.
sbi

1
@Marcus: Bunlar Boost.Range'den çok daha eskidir. :)
sbi

4
@Roger: Standart lib ile kullanılmaları için dizileri sarar. İşte gidiyorsun. :)
sbi

2
@Stacked, @sbe: Diziler, bir &. Dizinin &uzunluğunun tür çıkarımını etkinleştirmek için var.
Mankarse

12

Bazen varmış gibi hissediyorum begin()ve end()cehennemde. Aşağıdaki gibi bazı işlevlere sahip olmak istiyorum:

template<typename T>
void sort(T& x)
{
    std::sort(x.begin(), x.end());
}

ve diğer benzer olanlar std::find, std::for_eachve temelde tüm STL algoritmaları.

Bunun sort(x)okumak / anlamaktan çok daha hızlı olduğunu hissediyorum sort(x.begin(), x.end()).


1
ipucu; bunun yerine ´sort (boost :: begin (x), boost: end (x)); ´ kullanın ve dizileri de sıralayabilirsiniz.
Viktor Sehr

4
Boost.Range v2, tüm standart kitaplık için buna benzer bağdaştırıcılara sahiptir.
ildjarn

9

Bunu artık neredeyse pek kullanmıyorum ama eskiden temel bir üründü:

template<typename T>
std::string make_string(const T& data) {
    std::ostringstream stream;
    stream << data;
    return stream.str();
}

Hatırladıkça daha fazlasıyla güncellenecek. : P


3
Hehe - bir çeşit kısayol boost::lexical_cast<t, t>.
Billy ONeal

1
evet, bir projeye güç katmak istemiyorsanız bu harika
Steve

11
@BillyONeal: Artık kullanmamamın nedeni bu. @Steve: Hala kullanmamın nedeni bu.
Jon Purdy

Bunu a char*veya a ile aramak gereksiz yere pahalı olur std::string. Belki bir şablon uzmanlığı sırayla?
wilhelmtell

Doğru hatırlıyorsam boost::lexical_cast, böyle uzmanlıklar ve hata kontrolleri var. Tek sayıyı dizgiye çevirmek için bu gayet iyi çalışıyor.
Jon Purdy

9

Herkesin araç kutusundaki fayda işlevi elbette copy_if. Gerçi gerçekten bir paketleyici değil.

Yaygın olarak kullandığım bir başka yardımcı da deleter, std::for_eachbir kaptaki tüm işaretçileri silmek için kullandığım bir işlevdir .

[değiştir] "sth.h" adımı karıştırırken şunu da buldum vector<wstring> StringSplit(wstring const&, wchar_t);


Silme işlevleri için +1. Silici işlevim çoğu kapta iyi çalışıyor, ancak anahtarın veya değerin bir işaretçi olduğu std :: map ile çalışmasını sağlamakla uğraşıyorum. Sorunu çözmek için tür özelliklerini kullanmayı denedim, ancak zaman kısıtlamaları nedeniyle gerçekten çok ileri gitmedim. Bu sorunu çözdünüz mü yoksa bir sorun olarak görüyor musunuz?
Glen

2
@Matthieu M. maalesef hepimiz boost kullanamıyoruz.
Glen

@Glen: Tüm bu sorunlar akıllı işaretçiler kullanılarak, tercihen (ancak zorunlu olarak değil) boosttan çözülebilir. Önemli bir yan etki olarak, dinamik olarak tahsis edilmiş nesnelere işaret eden kaplar aniden istisnai güvenli hale gelir.
sbi

@Glen burada, Boost veya TR1 dahil olmak üzere STD dışında herhangi bir kitaplık öngörmeyen projeler için burada.
buğdaylar

7
@ kurumsal aptallığın talihsiz kurbanları: kurum içi kütüphaneler için bir istisna yapın, ardından Boost'un faydalı parçalarını şirket içi kütüphaneye aktarın. Siyasette bile tüm sorunlar başka bir dolaylı yoldan çözülebilir.
MSalters

9

Aşağıdakileri "util" ad alanına yerleştiren bir başlığım var:

// does a string contain another string
inline bool contains(const std::string &s1, const std::string &s2) {
    return s1.find(s2) != std::string::npos;
}

// remove trailing whitespace
inline std::string &rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}

// remove leading whitespace
inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

// remove whitespace from both ends
inline std::string &trim(std::string &s) {
    return ltrim(rtrim(s));
}

// split a string based on a delimeter and return the result (you pass an existing vector for the results)
inline std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

// same as above, but returns a vector for you
inline std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

// does a string end with another string
inline bool endswith(const std::string &s, const std::string &ending) {
    return ending.length() <= s.length() && s.substr(s.length() - ending.length()) == ending;
}

// does a string begin with another string  
inline bool beginswith(const std::string &s, const std::string &start) {
    return s.compare(0, start.length(), start) == 0;
}

2
Bu , çok kısa olan bir vektörü sessizce döndürerek, split()içinde meydana gelen tüm hataları yutar std::getline().
sbi

tabii ki size()dizelerinizi almadan önce sonucu kontrol etmelisiniz .
Evan Teran

Ve sonucun kaç dizeye sahip olması gerektiğini nasıl bilebilirim?
sbi

2
@sbi: Yorumunuz, stringstream/ getlinedöngüsü ile neyin yanlış gidebileceğine dair ilgimi doruğa çıkardı (dizenin basitçe elde etmek için yeterli jetona sahip olmaması dışında) . Burada bununla ilgili bir soru sordum: stackoverflow.com/questions/2562906/…
Evan Teran

2
@Evan: Düzeltilmiş durumdayım. Stackoverflow.com/2563542#2563542 adresindeki yorumuma bakın . Afedersiniz.
sbi

8

Kötü şöhretli eksik erasealgoritma:

  template <
    class Container,
    class Value
    >
  void erase(Container& ioContainer, Value const& iValue)
  {
    ioContainer.erase(
      std::remove(ioContainer.begin(),
                  ioContainer.end(),
                  iValue),
       ioContainer.end());
  } // erase

  template <
    class Container,
    class Pred
    >
  void erase_if(Container& ioContainer, Pred iPred)
  {
    ioContainer.erase(
      std::remove_if(ioContainer.begin(),
                     ioContainer.end(),
                     iPred),
       ioContainer.end());
  } // erase_if

+1, benimki tam olarak eşdeğerini göndermek üzereydi. Ona remove_erase (...) adını vermiş olsam da
Viktor Sehr

2
Bununla ilgili tek sorun, STL'de beklenen semantik silme-kaldırma deyimini bozmasıdır. Anlamsallığı kaldıran herhangi bir algoritmada sil-kaldır deyimine ihtiyacınız var - sadece değil std::remove. Örneğin std::unique,.
Billy ONeal

Pekala, bunun için çoğu STL algoritmasının kapsayıcı uyarlamalarına sahibim :) Ama bu benim en çok kullandığım, genellikle benzersizlik istiyorsam, başlangıçta a kullanıyorum set.
Matthieu M.

@Matthieu M .: Bunu yaparak STL ile çalışan insanların kafalarında sürekli alarm zilleri çalacağını unutmayın "UYARI: SİLİNMEYEN BİR ÇAĞRI OLMADAN ALGORİTMİ KALDIRIN !!" . Bunda gerçekten yanlış bir şey yok, ancak kodumu birçok programcı arasında paylaşmam gerekirse yapacağım bir şey değil. Sadece 2 sentim.
Billy ONeal

1
@Billy: Bu yüzden ona silme ve silme ismini verdim. Koda başvurmalarına izin vermekten başka yapabileceğim pek bir şey yok. Neyse ki modern IDE ile tanım sadece bir tık uzakta :)
Matthieu M.

7

Sprintf sarma

string example = function("<li value='%d'>Buffer at: 0x%08X</li>", 42, &some_obj);
// 'function' is one of the functions below: Format or stringf

Amaç, sprintf ve benzeri ile sorun yaşamadan biçimlendirmeyi çıktıdan ayırmaktır . Hoş değil, ama çok kullanışlıdır, özellikle kodlama yönergeleriniz yayın akışlarını yasaklıyorsa.


Neil Butterworth'tan gerektiği gibi tahsis eden bir versiyon burada. [Kalan ikisinin alt kümesi olarak kaldırdığım Mike'ın sürümünün düzeltme geçmişini görüntüleyin. Neil'inkine benzer, ancak ikincisi, delete [] yerine vektör kullanılarak istisnai güvenliklidir: string'in ctoru, ayırma başarısızlığına yol açar. Mike's ayrıca boyutu önceden belirlemek için daha sonra gösterilen aynı tekniği kullanır. –RP]

string Format( const char * fmt, ... ) {
  const int BUFSIZE = 1024;
  int size = BUFSIZE, rv = -1;
  vector <char> buf;
  do {
    buf.resize( size );
    va_list valist;
    va_start( valist, fmt );
    // if _vsnprintf() returns < 0, the buffer wasn't big enough
    // so increase buffer size and try again
    // NOTE: MSFT's _vsnprintf is different from C99's vsnprintf,
    //       which returns non-negative on truncation
    //       http://msdn.microsoft.com/en-us/library/1kt27hek.aspx
    rv = _vsnprintf( &buf[0], size, fmt, valist );
    va_end( valist );
    size *= 2;
  }
  while( rv < 0 );
  return string( &buf[0] );
}

Roger Pate'den gerekli boyutu önceden belirleyen bir versiyon burada . Bu, popüler uygulamalar tarafından sağlanan, ancak C ++ 0x için açıkça gerekli olan yazılabilir std :: dizeleri gerektirir. [Biraz farklı olduğu, ancak esasen aşağıdakilerin bir alt kümesi olduğu için kaldırdığım Marcus'un sürümünün revizyon geçmişini görüntüleyin. –RP]

Uygulama

void vinsertf(std::string& s, std::string::iterator it,
             char const* fmt, int const chars_needed, va_list args
) {
  using namespace std;
  int err; // local error code
  if (chars_needed < 0) err = errno;
  else {
    string::size_type const off = it - s.begin(); // save iterator offset
    if (it == s.end()) { // append to the end
      s.resize(s.size() + chars_needed + 1); // resize, allow snprintf's null
      it = s.begin() + off; // iterator was invalidated
      err = vsnprintf(&*it, chars_needed + 1, fmt, args);
      s.resize(s.size() - 1); // remove snprintf's null
    }
    else {
      char saved = *it; // save char overwritten by snprintf's null
      s.insert(it, chars_needed, '\0'); // insert needed space
      it = s.begin() + off; // iterator was invalidated
      err = vsnprintf(&*it, chars_needed + 1, fmt, args);
      *(it + chars_needed) = saved; // restore saved char
    }

    if (err >= 0) { // success
      return;
    }
    err = errno;
    it = s.begin() + off; // above resize might have invalidated 'it'
    // (invalidation is unlikely, but allowed)
    s.erase(it, it + chars_needed);
  }
  string what = stringf("vsnprintf: [%d] ", err);
  what += strerror(err);
  throw runtime_error(what);
}

Genel arayüz

std::string stringf(char const* fmt, ...) {
  using namespace std;
  string s;
  va_list args;
  va_start(args, fmt);
  int chars_needed = vsnprintf(0, 0, fmt, args);
  va_end(args);
  va_start(args, fmt);
  try {
    vinsertf(s, s.end(), fmt, chars_needed, args);
  }
  catch (...) {
    va_end(args);
    throw;
  }
  va_end(args);
  return s;
}

// these have nearly identical implementations to stringf above:
std::string& appendf(std::string& s, char const* fmt, ...);
std::string& insertf(std::string& s, std::string::iterator it,
                    char const* fmt, ...);

@Neil: Gönderen man vsnprintf: "Bu işlevler bir çıkış hatası oluşursa, baskılı karakter sayısını ... ya da negatif bir değer döndürür haricinde için snprintf()ve vsnprintf()n sınırsız olsaydı baskılı olurdu karakter sayısını döndürür, hangi ... "Bu nedenle, gerekli arabellek boyutunu ölçmek için kukla bir 0 arabelleği çağırır.
Mike DeSimone

@Checkers: Ah, Boost. Öyle büyük bir potansiyel ki benim de kullanmama izin vermiyorlar. Umarım bir gün. Her neyse, Boost henüz tam olarak anlaşılamayacak kadar büyüdü mü? Sadece aldığım için mutlu olurum boost::spirit.
Mike DeSimone

Bu aslında Windows kodudur - MSDN'den "_vsnprintf için, yazılacak bayt sayısı arabelleği aşarsa, bayt sayısı yazılır ve –1 döndürülür." ama onu Linux'a taşıyorum. Linux uygulamamın bunu gerçekten kullanıp kullanmadığını veya büyük arabellek boyutları için test edip etmediğimi hatırlayamıyorum - bunu yapmalıyım. Teşekkürler.

1
Yine de Windows kodunu kullanıyorsanız, devam edin ve _vscprintfgerekli arabellek boyutunu belirlemek için kullanın .
smerlin

6

Yardımcı is_sortedprogram, includesıralı bir giriş bekleyen gibi algoritmaları uygulamadan önce kapsayıcıları test etmek için :

  template <
    class FwdIt
  >
  bool is_sorted(FwdIt iBegin, FwdIt iEnd)
  {
    typedef typename std::iterator_traits<FwdIt>::value_type value_type;
    return adjacent_find(iBegin, iEnd, std::greater<value_type>()) == iEnd;
  } // is_sorted

  template <
    class FwdIt,
    class Pred
  >
  bool is_sorted_if(FwdIt iBegin, FwdIt iEnd, Pred iPred)
  {
    if (iBegin == iEnd) return true;
    FwdIt aIt = iBegin;
    for (++aIt; aIt != iEnd; ++iBegin, ++aIt)
    {
      if (!iPred(*iBegin, *aIt)) return false;
    }
    return true;
  } // is_sorted_if

Evet, biliyorum, yüklemi reddetmek ve yüklemeyi kullanmak daha iyi olur adjacent_find:)


1
testi yalnızca assert(): p
wilhelmtell

Macar gösterimini kullanmamalısınız.
the_drow

3
@the_drow: Bu faydalı yorum için çok teşekkür ederim :) Bunun hayranı değilim, ama çalıştığım bir gereklilik ... O zamandan beri alışkanlığı bıraktım, ruhum için endişelenme;)
Matthieu M.


3
//! \brief Fills reverse_map from map, so that all keys of map 
//         become values of reverse_map and all values become keys. 
//! \note  This presumes that there is a one-to-one mapping in map!
template< typename T1, typename T2, class TP1, class TA1, class TP2, class TA2 >
inline void build_reverse_map( const std::map<T1,T2,TP1,TA1>& map
                             ,       std::map<T2,T1,TP2,TA2>& reverse_map)
{
    typedef std::map<T1,T2,TP1,TA1>         map_type;
    typedef std::map<T2,T1,TP2,TA2>         r_map_type;
    typedef typename r_map_type::value_type r_value_type;

    for( typename map_type::const_iterator it=map.begin(),
                                          end=map.end(); it!=end; ++it ) {
        const r_value_type v(it->second,it->first);
        const bool was_new = reverse_map.insert(v).second;
        assert(was_new);
    }
}

Boost.BimapKitaplığı kullanmayı tercih ederim (veya Boost.MultiIndexdaha karmaşık durumlar için)
Matthieu M.

1
Anlamıyorum, neden assert ()?
Viktor Sehr

@Viktor: içinde yinelenen anahtar olmadığından emin olmak için reverse_map. Has map(1 -> "bir"; 2 -> "bir") reverse_mapbir öğe ("bir" -> 1) alacaktır. İddiaçi bunu yakalayacaktır. Ayrıca bakınız:
bijection

3
Btw, sbi, bir assert () içinde yan etkilere sahip bir koda sahip olmak, NDEBUG ile derleme yaptığınızda ve assert () lerin tamamen çıkarılmasından sonra sizi oldukça kötü bir şekilde ısırır.
sbk

2
gah, güncellemeden sonra ilk yorumum gerçekten aptalca görünüyor, stackoverflow 1 numara, bu yüzden gelecekteki hiçbir işveren bunu görmez umarım =)
Viktor Sehr

3

Benim stl_util.h, klasiklerin çoğuna (silme işlevleri copy_if) ve ayrıca buna (muhtemelen oldukça yaygındır, ancak şu ana kadar yanıtlarda verilmiş görmüyorum) bir haritada arama yapmak ve bulunan değeri ya da bir varsayılan, ala getPython'un dict:

template<typename K, typename V>
inline V search_map(const std::map<K, V>& mapping,
                    const K& key,
                    const V& null_result = V())
   {
   typename std::map<K, V>::const_iterator i = mapping.find(key);
   if(i == mapping.end())
      return null_result;
   return i->second;
   }

Varsayılan olarak null_resultoluşturulmuş bir varsayılanın kullanılması, s öğesinin Vdavranışıyla aynıdır , ancak bu, harita const olduğunda (benim için ortak) veya varsayılan olarak oluşturulmuş V kullanılacak doğru şey değilse yararlıdır.std::mapoperator[]


Ya V bir int veya float veya başka bir ilkelse?
ters

Boş değer başlatma, C ++ 'daki temel türler için çalışır. Tam sayılar ve kayan sayılar için bu, varsayılan null_result 0 olur.
Jack Lloyd

3

İşte bazı işlevler için ihtiyaç duyabileceğiniz bir boost.range'ish std-algo sarmalayıcısının üzerine oluşturulmuş ekstra araçlar setim. (yazmak önemsiz, bu ilginç şeyler)

#pragma once


/** @file
    @brief Defines various utility classes/functions for handling ranges/function objects
           in addition to bsRange (which is a ranged version of the \<algorithm\> header)

    Items here uses a STL/boost-style naming due to their 'templatised' nature.

    If template variable is R, anything matching range_concept can be used. 
    If template variable is C, it must be a container object (supporting C::erase())
*/

#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/smart_ptr.hpp>

namespace boost
{
struct use_default; 

template<class T>
class iterator_range;

#pragma warning(disable: 4348) // redeclaration of template default parameters (this clashes with fwd-decl in boost/transform_iterator.hpp)
template <
    class UnaryFunction
  , class Iterator
  , class Reference = use_default
  , class Value = use_default
>
class transform_iterator;

template <
    class Iterator
  , class Value = use_default
  , class Category   = use_default
  , class Reference  = use_default
  , class difference = use_default
>
class indirect_iterator;

template<class T>
struct range_iterator;

template <
    class Incrementable
  , class CategoryOrTraversal = use_default
  , class difference = use_default
>
class counting_iterator;

template <class Predicate, class Iterator>
class filter_iterator;

}

namespace orz
{

/// determines if any value that compares equal exists in container
template<class R, class T>
inline bool contains(const R& r, const T& v) 
{
    return std::find(boost::begin(r), boost::end(r), v) != boost::end(r);
}

/// determines if predicate evaluates to true for any value in container
template<class R, class F>
inline bool contains_if(const R& r, const F& f) 
{
    return std::find_if(boost::begin(r), boost::end(r), f) != boost::end(r);
}

/// insert elements in range r at end of container c
template<class R, class C>
inline void insert(C& c, const R& r)
{
    c.insert(c.end(), boost::begin(r), boost::end(r));
}
/// copy elements that match predicate
template<class I, class O, class P>
inline void copy_if(I i, I end, O& o, const P& p)
{
    for (; i != end; ++i) {
        if (p(*i)) {
            *o = *i;
            ++o;
        }
    }
}

/// copy elements that match predicate
template<class R, class O, class P>
inline void copy_if(R& r, O& o, const P& p)
{
    copy_if(boost::begin(r), boost::end(r), o, p);
}

/// erases first element that compare equal
template<class C, class T>
inline bool erase_first(C& c, const T& v) 
{
    typename C::iterator end = boost::end(c);
    typename C::iterator i = std::find(boost::begin(c), end, v);
    return i != c.end() ? c.erase(i), true : false;
}

/// erases first elements that match predicate
template<class C, class F>
inline bool erase_first_if(C& c, const F& f) 
{
    typename C::iterator end = boost::end(c);
    typename C::iterator i = std::find_if(boost::begin(c), end, f);
    return i != end ? c.erase(i), true : false;
}

/// erase all elements (doesn't deallocate memory for std::vector)
template<class C>
inline void erase_all(C& c) 
{
    c.erase(c.begin(), c.end());
}

/// erase all elements that compare equal
template<typename C, typename T>
int erase(C& c, const T& value)
{
    int n = 0;

    for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) {
        if (*i == value) {
            i = c.erase(i);
            ++n;
        } else {
            ++i;
        }
    }

    return n;
}

/// erase all elements that match predicate
template<typename C, typename F>
int erase_if(C& c, const F& f)
{
    int n = 0;

    for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) {
        if (f(*i)) {
            i = c.erase(i);
            ++n;
        } else {
            ++i;
        }
    }

    return n;
}


/// erases all consecutive duplicates from container (sort container first to get all)
template<class C>
inline int erase_duplicates(C& c)
{
    boost::range_iterator<C>::type i = std::unique(c.begin(), c.end());
    typename C::size_type n = std::distance(i, c.end());
    c.erase(i, c.end());
    return n;
}

/// erases all consecutive duplicates, according to predicate, from container (sort container first to get all)
template<class C, class F>
inline int erase_duplicates_if(C& c, const F& f)
{
    boost::range_iterator<C>::type i = std::unique(c.begin(), c.end(), f);
    typename C::size_type n = std::distance(i, c.end());
    c.erase(i, c.end());
    return n;
}

/// fill but for the second value in each pair in range
template<typename R, typename V>
inline void fill_second(R& r, const V& v)
{
    boost::range_iterator<R>::type i(boost::begin(r)), end(boost::end(r));

    for (; i != end; ++i) {
        i->second = v;
    }
}

/// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications
template<typename R1, typename R2, typename F>
void for_each2(R1& r1, R2& r2, const F& f)
{
    boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1));
    boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2));

    for(;i != i_end && j != j_end; ++i, ++j) {
        f(*i, *j);
    }    
}

/// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications
template<typename R1, typename R2, typename R3, typename F>
void for_each3(R1& r1, R2& r2, R3& r3, const F& f)
{
    boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1));
    boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2));
    boost::range_iterator<R3>::type k(boost::begin(r3)), k_end(boost::end(r3));

    for(;i != i_end && j != j_end && k != k_end; ++i, ++j, ++k) {
        f(*i, *j, *k);
    }    
}


/// applying function to each possible permutation of objects, r1.size() * r2.size() applications
template<class R1, class R2, class F>
void for_each_permutation(R1 & r1, R2& r2, const F& f)
{
    typedef boost::range_iterator<R1>::type R1_iterator;
    typedef boost::range_iterator<R2>::type R2_iterator;

    R1_iterator end_1 = boost::end(r1);
    R2_iterator begin_2 = boost::begin(r2);
    R2_iterator end_2 = boost::end(r2);

    for(R1_iterator i = boost::begin(r1); i != end_1; ++i) {
        for(R2_iterator j = begin_2; j != end_2; ++j) {
            f(*i, *j);
        }
    }
}

template <class R>
inline boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > 
make_indirect_range(R& r)
{
    return boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > (r);
}

template <class R, class F>
inline boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> > 
make_transform_range(R& r, const F& f)
{
    return boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> >(
        boost::make_transform_iterator(boost::begin(r), f), 
        boost::make_transform_iterator(boost::end(r), f));
}

template <class T>
inline boost::iterator_range<boost::counting_iterator<T>  >
make_counting_range(T begin, T end)
{
    return boost::iterator_range<boost::counting_iterator<T> >(
        boost::counting_iterator<T>(begin), boost::counting_iterator<T>(end));
}

template <class R, class F>
inline boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >
make_filter_range(R& r, const F& f)
{
    return boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >(
        boost::make_filter_iterator(f, boost::begin(r), boost::end(r)),
        boost::make_filter_iterator(f, boost::end(r), boost::end(r)));
}

namespace detail {

template<class T>
T* get_pointer(T& p) {
    return &p;
}

}

/// compare member function/variable equal to value. Create using @ref mem_eq() to avoid specfying types 
template<class P, class V>
struct mem_eq_type
{
    mem_eq_type(const P& p, const V& v) : m_p(p), m_v(v) { }

    template<class T>
    bool operator()(const T& a) const {
        using boost::get_pointer;
        using orz::detail::get_pointer;
        return (get_pointer(a)->*m_p) == m_v;
    }

    P m_p;
    V m_v;
};


template<class P, class V>
mem_eq_type<P,V> mem_eq(const P& p, const V& v) 
{
    return mem_eq_type<P,V>(p, v);
}

/// helper macro to define function objects that compare member variables of a class
#define ORZ_COMPARE_MEMBER(NAME, OP) \
    template <class P> \
    struct NAME##_type \
    { \
        NAME##_type(const P&p) : m_p(p) {} \
        template<class T> \
        bool operator()(const T& a, const T& b) const { \
            return (a.*m_p) OP (b.*m_p); \
        } \
        P m_p; \
    }; \
    template <class P> \
    NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); }

#define ORZ_COMPARE_MEMBER_FN(NAME, OP) \
    template <class P> \
    struct NAME##_type \
    { \
        NAME##_type(const P&p) : m_p(p) {} \
        template<class T> \
        bool operator()(const T& a, const T& b) const { \
        return (a.*m_p)() OP (b.*m_p)(); \
    } \
        P m_p; \
    }; \
    template <class P> \
    NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); }

/// helper macro to wrap range functions as function objects (value return)
#define ORZ_RANGE_WRAP_VALUE_2(FUNC, RESULT)                              \
    struct FUNC##_                                                \
    {                                                             \
        typedef RESULT result_type;                               \
        template<typename R, typename F>                          \
        inline RESULT operator() (R&  r, const F&  f) const       \
        {                                                         \
            return FUNC(r, f);                                    \
        }                                                         \
    };

/// helper macro to wrap range functions as function objects (void return)
#define ORZ_RANGE_WRAP_VOID_2(FUNC)                                 \
    struct FUNC##_                                                \
    {                                                             \
        typedef void result_type;                                 \
        template<typename R, typename F>                          \
        inline void operator() (R&  r, const F&  f) const         \
        {                                                         \
            FUNC(r, f);                                           \
        }                                                         \
    };

/// helper macro to wrap range functions as function objects (void return, one argument)
#define ORZ_RANGE_WRAP_VOID_1(FUNC)                                 \
    struct FUNC##_                                                \
    {                                                             \
        typedef void result_type;                                 \
        template<typename R>                          \
        inline void operator() (R&  r) const         \
        {                                                         \
            FUNC(r);                                           \
        }                                                         \
    }; 

ORZ_RANGE_WRAP_VOID_2(for_each);
ORZ_RANGE_WRAP_VOID_1(erase_all);
ORZ_RANGE_WRAP_VALUE_2(contains, bool);
ORZ_RANGE_WRAP_VALUE_2(contains_if, bool);
ORZ_COMPARE_MEMBER(mem_equal, ==)
ORZ_COMPARE_MEMBER(mem_not_equal, !=)
ORZ_COMPARE_MEMBER(mem_less, <)
ORZ_COMPARE_MEMBER(mem_greater, >)
ORZ_COMPARE_MEMBER(mem_lessequal, <=)
ORZ_COMPARE_MEMBER(mem_greaterequal, >=)
ORZ_COMPARE_MEMBER_FN(mem_equal_fn, ==)
ORZ_COMPARE_MEMBER_FN(mem_not_equal_fn, !=)
ORZ_COMPARE_MEMBER_FN(mem_less_fn, <)
ORZ_COMPARE_MEMBER_FN(mem_greater_fn, >)
ORZ_COMPARE_MEMBER_FN(mem_lessequal_fn, <=)
ORZ_COMPARE_MEMBER_FN(mem_greaterequal_fn, >=)

#undef ORZ_COMPARE_MEMBER
#undef ORZ_RANGE_WRAP_VALUE_2
#undef ORZ_RANGE_WRAP_VOID_1
#undef ORZ_RANGE_WRAP_VOID_2
}

For_each_permutation (...) için +1 , temelde benzer bir sarmalayıcı yazdığım için =). Peki neden erase_duplicates (...) işaretli bir int döndürür?
Viktor Sehr

Merhaba Viktor! Sen gördük gerektiğini for_each_permutation çok önceki işinde, sanırım. ;) erase_duplicates , günlüğe kaydetme ve hata ayıklama için yararlı olan silinen öğelerin sayısını döndürür.
Macke

Hmm, ne yaptığını anlamadan göz atmış olabilir ;) , neyse, neden bir tamsayı döndürdüğünü anlıyorum, tam sayının neden işaretli olduğunu anlamıyorum (veya daha spesifik olmak gerekirse; neden işaretsiz değil )?
Viktor Sehr

Ah. Benim açımdan sadece tembellik: -P. size_t uygun türdür.
Macke

3

Kartezyen bir ürüne ihtiyacım var gibi görünüyor, örneğin {A, B}, {1, 2} -> {(A, 1), (A, 2), (B, 1), (B, 2)}

// OutIt needs to be an iterator to a container of std::pair<Type1, Type2>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt
cartesian_product(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt out)
{
    for (; first1 != last1; ++first1)
        for (InIt2 it = first2; it != last2; ++it)
            *out++ = std::make_pair(*first1, *it);
    return out;
}

InIt2'nin bir girdi yineleyicisi yerine bir ileri yineleyici olması gerektiğini unutmayın . Giriş yineleyicileri, çoklu geçişler için uygun değildir.

2

Böyle bir ekleme işlevini adıyla çağırırdım ve + =, operatör * = operatörünü kullanırdım, örneğin:

    template<typename X> inline void operator+= (std::vector<X>& vec1, const X& value)
    {
      std::transform( vec1.begin(), vec1.end(), vec1.begin(), std::bind2nd(std::plus<X>(),value) );
    }

    template<typename X> inline void operator+= (std::vector<X>& vec1, const std::vector<X>& vec2)
    {
      std::transform( vec1.begin(), vec1.end(), vec2.begin(), vec1.begin(), std::plus<X>() );
    }

daha önce ima edildiği gibi diğer bazı basit ve bariz paketleyiciler:

    template<typename X> inline void sort_and_unique(std::vector<X> &vec)
    {
        std::sort( vec.begin(), vec.end() );
        vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() );
    }


    template<typename X> inline void clear_vec(std::vector<X> &vec)
    {
        std::vector<X>().swap(vec);
    }


    template<typename X> inline void trim_vec(std::vector<X> &vec, std::size_t new_size)
    {
        if (new_size<vec.size())
            std::vector<X>(vec.begin(),vec.begin() + new_size).swap(vec);
        else
            std::vector<X>(vec).swap(vec);
    }

7
Bu operatörler, operatör aşırı yüklemesinin neden nadiren yapılması gerektiğine çok iyi bir örnektir. Ben sanırdım vec+=valolurdu eklemek vektör bir değer. (Bkz. Stackoverflow.com/questions/2551775/. ) Uygulamanızı şimdi gördüğüme göre, bunun da anlamının bir yorumu olduğunu düşünüyorum +=. Sanırım yok muhtemelen de bu yüzden bir, doğru ya da yanlış olacağını bilemeyiz +=için std::vector.
sbi

1
@sbi Katılıyorum. Ben bulmak operator+()standardın inanılmaz erken fikir eksik. Artı işlecini gördüğüm her yerde genellikle bir O (1) işlemi bekliyorum. C ++, pahalı veya tehlikeli olan şeyleri daha ayrıntılı veya yapılması zor hale getirir ve bu şekilde hoşuma gider. Java'ya bir göz atın: en kötü kodlama hatalarından biri artı operatörünün kötüye kullanılmasıdır. Tabii ki, sonra tekrar, C ++ her zaman ucuz ve hızlı işleri kolaylaştırmaz, ama hey. İyi C ++ programcıları performansa çok duyarlıdır. ;)
wilhelmtell

2
op+()Belirsizliği nedeniyle tanımlanmaması gereken ikinize de katılıyorum . Ancak vektörler genellikle bir (matematiksel) vektör uzayının parçasıdır ve iki vektörün eklenmesinin ve skaler çarpımın kanonik bir tanımı vardır. Daha da argüman almak için: basit doublehem de bir vektör olup, iki eklersiniz eğer öyleyse doubledeğişkenleri gibi a+bo zaman yeni bir olsun beklersiniz doubledeğil, bir pairçift benzeri (a,b). Bir skaler ile çarpmak da kanoniktir, ancak iki vektörü çarpmak değildir. Bu yüzden aşırı yükleme dikkatli yapılmalıdır ..
Dane

1

Yeni bir öğe ekleyin ve onu iade edin, gibi basit hareket semantiği push_back(c).swap(value)ve ilgili durumlar için kullanışlıdır .

template<class C>
typename C::value_type& push_front(C& container) {
  container.push_front(typename C::value_type());
  return container.front();
}

template<class C>
typename C::value_type& push_back(C& container) {
  container.push_back(typename C::value_type());
  return container.back();
}

template<class C>
typename C::value_type& push_top(C& container) {
  container.push(typename C::value_type());
  return container.top();
}

Bir öğeyi açın ve iade edin:

template<class C>
typename C::value_type pop_front(C& container) {
  typename C::value_type copy (container.front());
  container.pop_front();
  return copy;
}

template<class C>
typename C::value_type pop_back(C& container) {
  typename C::value_type copy (container.back());
  container.pop_back();
  return copy;
}

template<class C>
typename C::value_type pop_top(C& container) {
  typename C::value_type copy (container.top());
  container.pop();
  return copy;
}

1

IMO'nun aşağıdakiler için daha fazla işlevselliğe ihtiyacı vardır pair:

#ifndef pair_iterator_h_
#define pair_iterator_h_

#include <boost/iterator/transform_iterator.hpp>    
#include <functional>
#include <utility>    

// pair<T1, T2> -> T1
template <typename PairType>
struct PairGetFirst : public std::unary_function<PairType, typename PairType::first_type>
{
    typename typename PairType::first_type& operator()(PairType& arg) const
    {       return arg.first;   }
    const typename PairType::first_type& operator()(const PairType& arg) const
    {       return arg.first;   }
};



// pair<T1, T2> -> T2
template <typename PairType>
struct PairGetSecond : public std::unary_function<PairType, typename PairType::second_type>
{
    typename PairType::second_type& operator()(PairType& arg) const
    {       return arg.second;  }
    const typename PairType::second_type& operator()(const PairType& arg) const
    {       return arg.second;  }
};



// iterator over pair<T1, T2> -> iterator over T1
template <typename Iter>
boost::transform_iterator<PairGetFirst<typename std::iterator_traits<Iter>::value_type>, Iter> 
make_first_iterator(Iter i)
{
    return boost::make_transform_iterator(i, 
        PairGetFirst<typename std::iterator_traits<Iter>::value_type>());
}



// iterator over pair<T1, T2> -> iterator over T2
template <typename Iter>
boost::transform_iterator<PairGetSecond<typename std::iterator_traits<Iter>::value_type>, Iter> 
make_second_iterator(Iter i)
{
    return boost::make_transform_iterator(i, 
        PairGetSecond<typename std::iterator_traits<Iter>::value_type>());
}



// T1 -> pair<T1, T2>
template <typename FirstType, typename SecondType>
class InsertIntoPair1st : public std::unary_function<FirstType, std::pair<FirstType, SecondType> >
{
public:
    InsertIntoPair1st(const SecondType& second_element) : second_(second_element) {}
    result_type operator()(const FirstType& first_element)
    {
        return result_type(first_element, second_);
    }
private:
    SecondType second_;
};



// T2 -> pair<T1, T2>
template <typename FirstType, typename SecondType>
class InsertIntoPair2nd : public std::unary_function<SecondType, std::pair<FirstType, SecondType> >
{
public:
    InsertIntoPair2nd(const FirstType& first_element) : first_(first_element) {}
    result_type operator()(const SecondType& second_element)
    {
        return result_type(first_, second_element);
    }
private:
    FirstType first_;
};

#endif // pair_iterator_h_

1
Neden hareket PairTypeoperatöre şablonu ()? Ayrıca, tanımlayıcıdaki çift alt çizgiler ayrılmıştır.
GManNickG

@GMan - Çünkü o zaman kullanamazsınız unary_function, ki benim kodumun bir noktasında ihtiyacım var. Çift alt çizgilere gelince, bana bildirdiğiniz için teşekkürler - bunu değiştirmem gerekecek.
rlbond

Bu, bağımlı isimleri (bağımsız değişken_türü, sonuç_türü) yanlış kullanır ve derleyicilerin bunu reddetmesi gerekir. "Bir sınıf şablonunun veya bir sınıf şablonunun bir üyesinin tanımında, sınıf şablonunun temel sınıfı bir şablon parametresine bağlıysa, temel sınıf kapsamı, nitelenmemiş ad araması sırasında ya da tanım noktasında incelenmez. sınıf şablonu veya üyesi veya sınıf şablonunun veya üyesinin somutlaştırılması sırasında. " [14.6.2 / 3, C ++ 03]

@ Roger Pate: Bu kuralın farkında değildim. Şimdi düzeltildi.
06'da

1
template <typename T> size_t bytesize(std::vector<T> const& v) { return sizeof(T) * v.size(); }

İşaretçi + bayt sayısı alan birçok işlevi kullanmanız gerekiyorsa, her zaman

fun(vec.data(), bytesize(vec));

1

* İle bir dizeyi çoğaltın:

std::string operator*(std::string s, size_t n)
{
    std::stringstream ss;
    for (size_t i=0; i<n; i++) ss << s;
    return ss.str();
}

0

Benim favorilerimden biri Transposer, aynı boyutta bir kap demetinin bir devrik bulmasıdır. Yani, eğer bir a sahipseniz tuple<vector<int>,vector<float>>, onu a'ya dönüştürür vector<tuple<int, float>>. XML programlamada kullanışlıdır. İşte böyle yaptım.

#include <iostream>
#include <iterator>
#include <vector>
#include <list>
#include <algorithm>
#include <stdexcept>

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <boost/type_traits.hpp>

using namespace boost;

template <class TupleOfVectors>
struct GetTransposeTuple;

template <>
struct GetTransposeTuple<tuples::null_type>
{
  typedef tuples::null_type type;
};

template <class TupleOfVectors>
struct GetTransposeTuple
{
  typedef typename TupleOfVectors::head_type Head;
  typedef typename TupleOfVectors::tail_type Tail;
  typedef typename
    tuples::cons<typename remove_reference<Head>::type::value_type,
                 typename GetTransposeTuple<Tail>::type> type;
};

template <class TupleOfVectors,
          class ValueTypeTuple = 
                typename GetTransposeTuple<TupleOfVectors>::type,
          unsigned int TUPLE_INDEX = 0>
struct Transposer
  : Transposer <typename TupleOfVectors::tail_type,
                ValueTypeTuple,
                TUPLE_INDEX + 1>
{
  typedef typename remove_reference<typename TupleOfVectors::head_type>::type
    HeadContainer;
  typedef typename TupleOfVectors::tail_type Tail;
  typedef Transposer<Tail, ValueTypeTuple, TUPLE_INDEX + 1> super;
  typedef std::vector<ValueTypeTuple> Transpose;

  Transposer(TupleOfVectors const & tuple)
    : super(tuple.get_tail()),
      head_container_(tuple.get_head()),
      head_iter_(head_container_.begin())
  {}

  Transpose get_transpose ()
  {
    Transpose tran;
    tran.reserve(head_container_.size());
    for(typename HeadContainer::const_iterator iter = head_container_.begin();
        iter != head_container_.end();
        ++iter)
    {
      ValueTypeTuple vtuple;
      this->populate_tuple(vtuple);
      tran.push_back(vtuple);
    }
    return tran;
  }

private:

  HeadContainer const & head_container_;
  typename HeadContainer::const_iterator head_iter_;

protected:

  void populate_tuple(ValueTypeTuple & vtuple)
  {
    if(head_iter_ == head_container_.end())
      throw std::runtime_error("Container bound exceeded.");
    else
    {
      vtuple.get<TUPLE_INDEX>() = *head_iter_++;
      super::populate_tuple (vtuple);
    }
  }
};

template <class ValueTypeTuple,
          unsigned int INDEX>
struct Transposer <tuples::null_type, ValueTypeTuple, INDEX>
{
  void populate_tuple(ValueTypeTuple &) {}
  Transposer (tuples::null_type const &) {}
};

template <class TupleOfVectors>
typename Transposer<TupleOfVectors>::Transpose
transpose (TupleOfVectors const & tupleofv)
{
  return Transposer<TupleOfVectors>(tupleofv).get_transpose();
}

int main (void)
{
  typedef std::vector<int> Vint;
  typedef std::list<float> Lfloat;
  typedef std::vector<long> Vlong;

  Vint vint;
  Lfloat lfloat;
  Vlong vlong;

  std::generate_n(std::back_inserter(vint), 10, rand);
  std::generate_n(std::back_inserter(lfloat), 10, rand);
  std::generate_n(std::back_inserter(vlong), 10, rand);

  typedef tuples::tuple<Vint, Lfloat, Vlong> TupleOfV;
  typedef GetTransposeTuple<TupleOfV>::type TransposeTuple;

  Transposer<TupleOfV>::Transpose tran = 
    transpose(make_tuple(vint, lfloat, vlong));
  // Or alternatively to avoid copying
  // transpose(make_tuple(ref(vint), ref(lfloat), ref(vlong)));
  std::copy(tran.begin(), tran.end(),
            std::ostream_iterator<TransposeTuple>(std::cout, "\n"));

  return 0;
}

0

Bunların standart sarmalayıcı olarak nitelendirilip nitelendirilmediğinden emin değilim, ancak yaygın olarak kullanılan yardımcı işlevlerim:

void split(string s, vector<string> parts, string delims);
string join(vector<string>& parts, string delim);
int find(T& array, const V& value);
void assert(bool condition, string message);
V clamp(V value, V minvalue, V maxvalue);
string replace(string s, string from, string to);
const char* stristr(const char* a,const char*b);
string trim(string str);
T::value_type& dyn(T& array,int index);

T ve V burada şablon argümanlarıdır. Son işlev, [] -operatör ile aynı şekilde çalışır, ancak gerekli dizine uyacak şekilde yeniden boyutlandırmayı otomatikleştirir.


1
'Assert' adı, bu ada sahip makrosu için standart kitaplık tarafından ayrılmıştır (tüm kapsamlarda).

1
Sanırım ayrıca windows veya mfc başlıklarında bildirilmiş bir assert () makrosu var. İkisi de WM_PAINT olayında başarısız olur, çünkü onaylama diyaloğunun görüntülenmesi bazı durumlarda sonraki atamayı tetikler. Sonuç olarak, bu hatalı uygulamaları üçüncü bir uygulamayla değiştirmek çok da önemli değil. Tek yapmanız gereken, #include <assert> sonrasında açıkça kendi assert-makrosunu yeniden beyan etmek veya sadece #undef assert kullanmaktır.
AareP

0

İnsanların daha önce yayınladıklarına benzer şekilde, yineleyici argümanlarını geçirmeyi basitleştirmek için kolaylık algoritmalarım var . Algoritmalara şöyle diyorum:

for_each(iseq(vec), do_it());

Tüm algoritmaları input_sequence_range<>, iki giriş yineleyicisi yerine tek bir tür parametresi alacak şekilde aşırı yükledim (yalnızca çıktı olmayan herhangi bir şeydeki gibi girdi).

template<typename In>
struct input_sequence_range
: public std::pair<In,In>
{
    input_sequence_range(In first, In last)
        : std::pair<In,In>(first, last)
    { }
};

Ve şu şekilde iseq()çalışır:

template<typename C>
input_sequence_range<typename C::const_iterator> iseq(const C& c)
{
    return input_sequence_range<typename C::const_iterator>(c.begin(),
                                                            c.end());
}

Benzer şekilde, uzmanlık alanım var

  • const_iterators
  • işaretçiler (ilkel diziler)
  • akış yineleyicileri
  • sadece tek tip kullanım için herhangi bir aralık [başlangıç, bitiş): her şey için iseq () kullanın

3
... veya sadece Boost.Range kullanabilir ve aralık adaptörlerinin ve meslektaş tarafından gözden geçirilmiş, geniş çapta test edilmiş kodun avantajlarından yararlanabilirsiniz.
Mankarse

0

İçin sırasız silme std::vector. Bir öğeyi a'dan silmenin en etkili yolu, vectorancak öğelerin sırasını korumaz. Ortadan öğeleri kaldırmak için çoğu kişi aynı cezaya sahip olmadığından, onu diğer konteynırlara genişletmenin anlamını görmedim. Zaten yayınlanan diğer şablonlara benzer, ancak std::swapöğeleri kopyalamak yerine taşımak için kullanır .

template<typename T>
void unordered_erase(std::vector<T>& vec, const typename std::vector<T>::iterator& it)
{
    if (it != vec.end()) // if vec is empty, begin() == end()
    {
        std::swap(vec.back(), *it);
        vec.pop_back();
    }
}

Signum, bir türün işaretini döndürür. İade -1negatif için, 0sıfır ve 1pozitifliği için.

template <typename T>
int signum(T val)
{
    return (val > T(0)) - (val < T(0));
}

Kelepçe oldukça açıklayıcıdır, verilen aralıkta kalması için bir değeri sıkıştırır. Standart Kitaplığın şunları içermesi minve maxiçermemesi aklımı karıştırıyor:clamp

template<typename T>
T clamp(const T& value, const T& lower, const T& upper)
{
    return value < lower ? lower : (value > upper ? upper : value);
}
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.