どのC ++標準ライブラリラッパー関数を使用していますか?


81

今朝尋ねられたこの質問は、C ++標準ライブラリに欠けていると思う機能と、ラッパー関数でギャップを埋めるためにどのように取り組んだのか疑問に思いました。たとえば、私自身のユーティリティライブラリには、ベクトル追加用の次の関数があります。

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

これは(多かれ少なかれ)任意のタイプをクリアするためのものです-std :: stack:のようなものに特に役立ちます

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

もう少しありますが、どれを使っているのか興味がありますか?ラッパー関数への回答を制限してください。つまり、コードは数行以内です。


9
イテレータをいじることは非常に一般的な間違いであるという理由だけで、範囲ではなくコンテナ全体に作用するようにSTLアルゴリズムのほとんどをラップしたことは重要ですか:)?
Matthieu M.

2
@Billy実際、CWは主観的な質問をするための言い訳にはなりません。タイトルを変えて、みんなを幸せにしていきます。

4
@kts:vector :: insertにはランダムアクセスイテレータが与えられているので、優れた実装ではコンパイル時のディスパッチを使用してそれ自体を実行します。

4
c.swap(C())コンテナをクリアするために書く方がいいのではないですか?
アレクサンドルC.

5
@Alexandre:それは許可されていません:一時的なものを非const参照にバインドします。C()。swap(c)は機能します。

回答:


37

ブースト::配列

含む(コンテナ、val)(非常にシンプルですが便利です)。

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(begin、end、value)

std :: removeの高速バージョンは、残りのオブジェクトの順序を保持しないことを除いて。

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

(ポッドタイプ(int、floatなど)のベクトルの場合、ほとんどすべてのオブジェクトが削除されます。std:: removeの方が速い場合があります)。


4
他の誰かが、その中には、代わりに呼び出すbool sorted=falseときsorted==trueに3番目のテンプレート()と特殊化が必要だと思いますか?binary_searchfind
kitsuneYMG 2010年

5
@kts:コンテナがソートされていることがわかっいる場合は、binary_searchを直接呼び出してください

2
boost :: array STLに相当するものは、最新のコンパイラ(
codewarrior

36

非常に多くの場合、ベクトルを特定の順序でアイテムのセットとして使用します(そして、明らかに、高速のis-this-element-in-the-setチェックが必要ない場合)。このような場合、erase()を呼び出すと要素が並べ替えられ、順序は気にならないため、時間の無駄になります。その場合、以下のO(1)関数が役立ちます。削除する要素の位置に最後の要素を移動するだけです。

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

良いもの。そのようにすることを考えていませんでした.. :)順序が重要でないときにこれらの操作を高速化する「バッグ」ラッパー(スタックとキューに似ています)があるはずです。
マッケ2010年

12
そして、C ++ 0xでは、v[index] = st::move(v.back()); v.pop_back();それが得るのとほぼ同じくらい効率的です。
GManNickG 2010年

@Matthieu:それらのタイムスタンプを見てください。:PIは、許可された編集時間をはるかに超えて、数時間後に気づきました。
GManNickG 2010

@GMan:これについてよろしいですか?v.pop_back()は、デストラクタが呼び出されるときに未定義の動作を引き起こす可能性があるように見えます。
Viktor Sehr 2010

1
@Viktor:移動セマンティクスは、「私はあなたのリソースを取得し、それだけです」という意味ではなく、「私はあなたのリソースを取得し、リソースのない状態にする」という意味です。言い換えると、移動セマンティクスは、オブジェクトが安全に破壊できることを確認する必要があります。非常に簡単です。ポインタをnullに設定するだけです。
GManNickG 2010

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&);
};

わかりました。これは思ったほど簡単ではないようですので、ここで説明します
。コンストラクターtemp_valueには、変数への参照と変数の元の値のコピーが格納されます。デストラクタでは、参照されている変数を元の値に復元します。したがって、構築と破棄の間の変数に何をしたとしても、temp_valueオブジェクトがスコープ外になるとリセットされます。
次のように使用します。

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
}

スコープガードトリックを使用する別のアプローチは次のとおりです。

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);
}

これはもう少し定型的なコードですが、よりクリーンな使用法が可能です。

#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);
}

ただし、クラスで使用する機能は削除されます。


同じ効果を達成するための3番目の方法は次のとおりです(デストラクタを投げる可能性のある問題に悩まされることはありません)。

実装:

//none -- it is built into the language

使用法:

#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:後で値を自動的に復元するためのものです。(そしてvalはctorから削除されるべきです。)

申し訳ありませんが、私はまだ迷っています(私はC ++を初めて使用します)、誰かがそれをすぐに馬鹿にすることができますか?
dreamlax 2010

1
@dreamlax:それを説明する説明文を回答に追加しました。今は理解できますか、それとも詳細を詳しく調べる必要がありますか?
sbi 2010

1
ああ、2番目のものはかなり賢いです。
jalf 2011

1
うーん、これの実際のユースケースは何ですか?
paulm 2013

22

実際にはラッパーではありませんが、悪名高い欠落していcopy_ifます。ここから

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
stdlibのラッパーではなく、質問に答えません。

10
@Roger Pate、はい、私は知っています、それが答えが「実際にはラッパーではありませんが....」という言葉で始まる理由です。
グレン

1
@Rogerの実装の詳細。本当に必要な場合は、の観点から実装できますremove_copy_if()。:p
wilhelmtell 2010

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
私も持っています。:) +1価値があるので、必要なのは2つだけです(constバージョンを捨てます)。配列がconstの場合は、Tになりますconst Uと、あなたは意図された機能を取得します。
GManNickG 2010年

@GMan:非constバージョンのみで一部のコードをコンパイルしないバージョンのGCCconstがありました。そのため、バージョンがあります。それはその特定のGCCバージョンのバグだったかもしれないので、私はそれらを削除します。
sbi 2010年

1
@マーカス:これらはBoost.Rangeよりはるかに古いです。:)
sbi 2010年

4
@Roger:標準のlibで使用できるように配列をラップします。そこに行きます。:)
sbi 2010年

2
@ Stacked、@ sbe:が存在するかどうかに関係なく、配列が値で渡されることはありません&&配列の長さの型推論ができるようにすることです。
マンカルス2011年

12

私はにいるように時々私が感じるbegin()end()地獄。次のような関数が欲しいのですが。

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

および他の類似のためのものstd::findstd::for_eachと、基本的にすべてのSTLアルゴリズム。

私はそれsort(x)がよりもはるかに速く読んだり理解したりできると感じていsort(x.begin(), x.end())ます。


1
ヒント; 代わりに「sort(boost :: begin(x)、boost:end(x));」を使用すると、配列も並べ替えることができます。
Viktor Sehr

4
Boost.Range v2には、標準ライブラリ全体にこのようなアダプタがあります。
ildjarn

9

私はもうこれをほとんど使用していませんが、以前は定番でした:

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

私がそれらを覚えているので、より多くで更新します。:P


3
Hehe--のショートカットのようなものですboost::lexical_cast<t, t>
Billy ONeal 2010年

1
ええ、プロジェクトにブーストを引き込みたくないのであれば、それは素晴らしいことです
Steve

11
@BillyONeal:それが私がもうそれを使わない理由です。@スティーブ:それは私がまだそれを使用する理由です。
Jon Purdy 2010年

char*またはで呼び出すと、不必要にコストがかかりstd::stringます。たぶん、テンプレートの特殊化が必要ですか?
wilhelmtell 2010

私が正しく覚えていればboost::lexical_cast、そのような専門分野とエラーチェックがたくさんあります。ただし、奇数を文字列化するには、これで問題ありません。
Jon Purdy 2010

9

もちろん、みんなのツールボックスのユーティリティ関数はですcopy_if。しかし、実際にはラッパーではありません。

私がよく使用するもう1つのヘルパーは、コンテナー内のすべてのポインターを削除するdeleterために使用するファンクターstd::for_eachです。

[編集]私も見つけた「sth.h」を掘り下げる vector<wstring> StringSplit(wstring const&, wchar_t);


削除ファンクターの場合は+1。私のデリッターファンクターはほとんどのコンテナーでうまく機能しますが、キーまたは値のいずれかがポインターであるstd :: mapで機能するように遊んでいます。型特性を使用して問題を解決しようとしましたが、時間の制約のため、それほど遠くはありませんでした。この問題を解決しましたか、それとも問題だと思いますか?
グレン

2
@Matthieu M.残念ながら、私たち全員がブーストを使用できるわけではありません。
グレン

@Glen:これらの問題はすべて、できれば(必ずしもそうとは限りませんが)ブーストからスマートポインターを使用することで解決できます。重要な副作用として、動的に割り当てられたオブジェクトへのポインタを持つコンテナも突然例外安全になります。
sbi 2010年

@Glen here、ここでは、BoostまたはTR1までのSTD以外のライブラリを規定しないプロジェクトの場合。
ウィーティーズ2010

7
@企業の愚かさの不幸な犠牲者:社内ライブラリの例外を取得してから、Boostの有用な部分を社内ライブラリにインポートします。政治においてさえ、すべての問題は別のレベルの間接参照で解決することができます。
MSalters 2010

9

「util」名前空間に以下を配置するヘッダーがあります。

// 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
これによりsplit()、で発生するエラーがすべて飲み込まれstd::getline()、短すぎるベクトルがサイレントに返されます。
sbi 2010

もちろん、size()文字列を取得する前に結果を確認する必要があります。
Evan Teran 2010

そして、結果に必要な文字列の数をどのように知ることができますか?
sbi 2010

2
@sbi:あなたのコメントは、stringstream/getlineループで実際に何がうまくいかない可能性があるか(文字列が単に取得するのに十分なトークンを持っていないことを除いて)についての私の興味をピークにしました。私はここでそれについての質問を提起しました:stackoverflow.com/questions/2562906/...
エヴァン・テラン

2
@エヴァン:私は正直に立っています。stackoverflow.com/2563542#2563542で私のコメントを参照してください。ごめんなさい。
sbi 2010

8

悪名高い欠落しているeraseアルゴリズム:

  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、私とまったく同じものを投稿しようとしていました。私はそれをremove_erase(...)と名付けましたが
Viktor Sehr

2
これに関する唯一の問題は、STLで期待されるセマンティック消去-削除イディオムを破ることです。だけでなく、removeセマンティクスを持つ任意のアルゴリズムでerase-removeイディオムが必要std::removeです。たとえば、std::unique
Billy ONeal 2010年

まあ、私はこれのためにほとんどのSTLアルゴリズムのコンテナ適応を持っています:)しかし、これは私が最も使用するものです、通常、私setが最初に使用する一意性が必要な場合。
Matthieu M.

@Matthieu M。:これを行うことで、STLを常に使用している人々の頭の中で警報ベルが鳴るということを覚えておいてください。「警告:消去する必要のないアルゴリズムのような削除!!」 。実際には何も問題はありませんが、多くのプログラマー間でコードを共有する必要がある場合は、私が行うことではありません。ちょうど私の2セント。
Billy ONeal 2010年

1
@ビリー:それが私がそれを削除ではなく消去と呼んだ理由です。コードを参照させる以外に、それ以外にできることはあまりありません。ありがたいことに、最新のIDEでは、定義はクリックするだけです:)
Matthieu M.

7

sprintfのラッピング

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

目標は、sprintfとその同類に問題を起こすことなく、フォーマットを出力から切り離すことです。きれいではありませんが、特にコーディングガイドラインでiostreamが禁止されている場合は非常に便利です。


これは、ニールバターワースから必要に応じて割り当てるバージョンです。[残りの2つのサブセットとして削除したMikeのバージョンの改訂履歴を表示します。これはNeilのものと似ていますが、後者はdelete []の代わりにvectorを使用することで例外安全である点が異なります。文字列のctorは、割り当ての失敗時にスローします。Mike'sも、後で示す同じ手法を使用して、事前にサイズを決定します。–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] );
}

これは、RogerPateから必要なサイズを事前に決定するバージョンです。これには、書き込み可能なstd :: stringが必要です。これは、一般的な実装によって提供されますが、C ++ 0xでは明示的に必要です。[マーカスのバージョンの改訂履歴を表示します。少し異なるため削除しましたが、基本的には以下のサブセットです。–RP]

実装

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);
}

パブリックインターフェイス

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:からman vsnprintf:「これらの関数は、出力エラーが発生した場合、印刷された文字の数...または負の値を返す以外ためsnprintf()vsnprintf()nが無制限であれば、印刷されていたであろう文字数を返しています、... "したがって、必要なバッファサイズを測定するために0バッファを使用したダミー呼び出し。
Mike DeSimone 2010年

@チェッカー:ああ、ブースト。彼らが私にも使わせないほどの大きな可能性。いつか、うまくいけば。とにかく、Boostはまだ完全に理解することが不可能なほど大きくなっていますか?取得するだけで嬉しいですboost::spirit
Mike DeSimone 2010年

これは実際にはWindowsコードです-MSDNから「_vsnprintfの場合、書き込むバイト数がバッファを超えると、カウントバイトが書き込まれ、-1が返されます。」しかし、私はそれをLinuxに移植します。Linuxアプリが実際にこれを使用しているかどうか、または大きなバッファーサイズでテストしたかどうかを思い出せません。使用する必要があります。ありがとう。

1
とにかくWindowsコードを使用する場合は、先に進んで、を使用_vscprintfして必要なバッファーのサイズを決定してください。
smerlin 2010年

6

is_sorted以下のようなアルゴリズムを適用する前に、テストコンテナへのユーティリティ、includeソートされたエントリを期待されました:

  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

ええ、私は知っています、述語を否定し、述語バージョンを使用する方が良いでしょうadjacent_find:)


1
assert():p
wilhelmtell 2010

ハンガリアン記法は使用しないでください。
the_drow 2011年

2
@the_drow:この有益なコメントをありがとうございました:)私はそれについてそれほどファンではありませんが、それは私が働く場所の要件です...私はそれ以来習慣を振り払ったので、私の魂を心配しないでください;)
Matthieu M.

3

間違いなくboost :: addressof


実際、私はオーバーロード&について多くの議論を聞いたことがありますが、実際に誰かがそれを行うのを見たことがありません(うーんbit_referenceかもしれません)。
Viktor Sehr 2010

@Victor Sehr:ATL :: CComPtr(msdn.microsoft.com/en-us/library/ezzw7k98(VS.80).aspx)および_com_ptr_t(msdn.microsoft.com/en-us/library/417w8b3b(VS.80 ).aspx)が良い例です。
シャープトゥース2010

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.Bimapライブラリを使用することを好みます(またはBoost.MultiIndexより複雑な状況の場合)
Matthieu M.

1
わからない、なぜassert()?
Viktor Sehr 2010年

@Viktor:に重複するキーがないことを確認しreverse_mapます。maphas(1-> "one"; 2-> "one")reverse_mapが1つの要素( "one"-> 1)を取得すると考えてください。アサートはそれをキャッチします。参照:全単射
sbk 2010年

3
ところで、sbi、assert()内に副作用のあるコードがあると、NDEBUGでコンパイルし、assert()が完全に削除されると、かなりひどく噛み付きます。
sbk 2010年

2
ああ、更新後、私の最初のコメントは本当にばかげているように見えます、私の名前をグーグルで検索するとき、stackoverflowは#1なので、将来の雇用者がこれを見ないことを願っています=)
Viktor Sehr 2010年

3

私のstl_util.h、多くの古典(削除関数、copy_if)、およびこれも(おそらく非常に一般的ですが、これまでのところ応答には表示されていません)、マップを検索して見つかった値またはデフォルト、getPythonのala 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;
   }

デフォルトの使用null_resultデフォルト-構築のことVの振る舞いと同じ同じくらいであるstd::mapoperator[]が、マップはconstの(私にとって共通)であるとき、またはデフォルト・構築Vが使用する正しいことではない場合に便利です。


Vがint、float、またはその他のプリミティブである場合はどうなりますか?
逆2010

空の値の初期化は、C ++の基本型で機能します。整数と浮動小数点数の場合、それがデフォルトnull_result 0になるだろう
ジャック・ロイド

3

これは、いくつかの関数に必要になる可能性のある、boost.range'ishstd-algoラッパーの上に構築されたextra-utilsのセットです。(書くのは簡単です、これは面白いものです)

#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(...)の+1 、主に同様のラッパーを作成したため=)。しかし、なぜerase_duplicates(...)がsigned intを返すのですか?
Viktor Sehr 2010年

こんにちはViktor!前の仕事でもfor_each_permutationを見るべきだったと思います。;)erase_duplicatesは、消去された要素の数を返します。これは、ロギングとデバッグに役立ちます。
マッケ2010

うーん、それが何をしているのかわからないまま閲覧したかもしれません;)とにかく、なぜ整数を返すのかわかりますが、整数が符号付きの理由はわかりません(より具体的には、符号なしでないのはなぜですか)?
Viktor Sehr 2010

ああ。私の側のただの怠惰:-P。size_tは適切なタイプです。
マッケ2010

3

デカルト積が必要なようです。たとえば、{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は、入力イテレータではなく、順方向イテレータである必要があることに注意してください。入力イテレータは、複数のパスには適していません。

2

このような追加関数をその名前で呼び出し、operator + =、operator * =などを要素ごとの操作に使用します。

    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>() );
    }

前に暗示されている他のいくつかの単純で明白なラッパー:

    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
これらの演算子は、演算子のオーバーロードがめったに行われない理由の非常に良い例です。私は、思ってもみなかったvec+=valでしょうアペンドベクトルに値を。(stackoverflow.com/questions/2551775/を参照してください)これであなたの実装を見たので、これも同様に正しい意味の解釈だと思い+=ます。どちらが正しいか間違っているかわからないので、おそらく私たちが持っていないのも同様+=ですstd::vector
sbi 2010

1
@sbi同意します。operator+()標準の驚くべき初期の洞察が欠けていることに気づきました。私は通常、plus演算子が表示されるすべての場所でO(1)演算を期待しています。C ++を使用すると、高価または危険なものがより冗長になるか、実行が困難になります。私はこの方法が気に入っています。Javaを見てください。最悪のコーディングミスの1つは、plus演算子の乱用です。もちろん、繰り返しになりますが、C ++は必ずしも安価で高速なものを簡単にするわけではありませんが、ちょっと。優れたC ++プログラマーは、パフォーマンスを非常に重視しています。;)
wilhelmtell 2010

2
op+()あいまいさのために定義されるべきではないあなたの両方に同意します。ただし、ベクトルは通常(数学的な)ベクトル空間の一部であり、2つのベクトルの加算とスカラー倍算の標準的な定義があります。さらに議論を進めると、単純doubleはベクトルでもあるので、のように2つのdouble変数を追加すると、のようなdoubleではなくa+b新しい変数を取得することが期待されます。スカラーを乗算することも標準的ですが、2つのベクトルを乗算することは標準的ではありません。だから、注意して行わなければならないオーバーロード...doublepair(a,b)
デーン

1

新しいアイテムを挿入して返します。これは、push_back(c).swap(value)関連するケースのような単純な移動セマンティクスに役立ちます。

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();
}

アイテムをポップして返品します。

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には、より多くの機能が必要です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
PairTypeテンプレートをoperator()に移動してみませんか?また、識別子の二重下線は予約されています。
GManNickG 2010

@ GMan-unary_functionコードのある時点で必要な、を使用できないためです。二重下線については、お知らせいただきありがとうございます。変更する必要があります。
rlbond 2010

これは従属名(argument_type、result_type)を誤って使用し、コンパイラーはそれを拒否する必要があります。「クラステンプレートまたはクラステンプレートのメンバーの定義で、クラステンプレートの基本クラスがテンプレートパラメータに依存している場合、非修飾名のルックアップ中に、定義の時点でも基本クラススコープは検査されません。クラステンプレートまたはメンバー、またはクラステンプレートまたはメンバーのインスタンス化中。」[14.6.2 / 3、C ++ 03]

@Roger Pate:私はそのルールに気づいていませんでした。現在修正されています。
rlbond 2010

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

ポインタ+バイト数をとる多くの関数を使用する必要がある場合、それは常に

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

1

文字列を*で複製します:

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

私のお気に入りの1つは、Transposer同じサイズのコンテナーのタプルの転置を見つけることです。つまり、があればtuple<vector<int>,vector<float>>、それをに変換しvector<tuple<int, float>>ます。XMLプログラミングに便利です。これが私がそれをした方法です。

#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

これらがstdラッパーとして適格かどうかはわかりませんが、私の一般的に使用されるヘルパー関数は次のとおりです。

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とVはテンプレート引数です。最後の関数は[] -operatorと同じように機能しますが、必要なインデックスに合わせてサイズ変更を自動化します。


1
「assert」という名前は、その名前のマクロ用に標準ライブラリによって(すべてのスコープで)予約されています。

1
Windowsまたはmfcヘッダーで宣言されたassert()マクロもあると思います。アサーションダイアログを表示すると次のアサーションがトリガーされる場合があるため、どちらもWM_PAINTイベントで失敗します。したがって、結局、これらのバグのある実装を3番目の実装に置き換えることは大したことではありません。#include <assert>の後に独自のassert-macroを明示的に再宣言するか、#undefassertを使用するだけです。
aareP 2010

0

人々は前に掲示するものと同様に、私が持っているイテレータ引数を渡す単純化するためのアルゴリズムの利便性のオーバーロードを。私はこのようなアルゴリズムを呼び出します:

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

input_sequence_range<>2つの入力イテレーター(単なる出力ではないもののように入力)ではなく、型の単一のパラメーターを受け取るように、すべてのアルゴリズムをオーバーロードしました。

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)
    { }
};

そして、これはどのようにiseq()機能するかです:

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());
}

同様に、私は

  • const_iterators
  • ポインター(プリミティブ配列)
  • ストリームイテレータ
  • 均一に使用するための任意の範囲[begin、end):すべてにiseq()を使用する

3
...または、Boost.Rangeを使用して、範囲アダプターとピアレビューされ、広くテストされたコードの利点を得ることができます。
マンカルス2011年

0

の順序なし消去std::vector。から要素を消去する最も効率的な方法ですが、要素vectorの順序は保持されません。ほとんどの場合、中央からアイテムを削除しても同じペナルティがないため、他のコンテナに拡張する意味がわかりませんでした。すでに投稿されている他のいくつかのテンプレートに似ていますstd::swapが、コピーする代わりにアイテムを移動するために使用します。

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はタイプの符号を返します。-1負の場合0、ゼロの場合、および1正の場合に戻ります。

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

クランプはかなり自明であり、指定された範囲内に収まるように値をクランプします。標準ライブラリに含まれていることは私の頭を悩ませますminているmaxがていないせますclamp

template<typename T>
T clamp(const T& value, const T& lower, const T& upper)
{
    return value < lower ? lower : (value > upper ? upper : value);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.