6

https://stackoverflow.com/a/709161/837451の例を使用して、スワップを介してstd::queue をクリアしようとしています。ただし、「削除された関数」エラーのため、ラムダコンパレータでは機能しないようです。

最小限働く失敗例:

#include <queue>
#include <vector>
using namespace std;
int main(){
    typedef pair<int,float> ifpair;
    auto comp = []( ifpair a,  ifpair b ) { return a.second > b.second; };
    typedef priority_queue< ifpair , vector<ifpair>, decltype( comp ) > t_npq;
    t_npq npq( comp );
    //do something with npq. finish using it (without emptying it) and clear for next round
    t_npq empty( comp );
    swap(npq , empty);
}

でコンパイル

g++ -std=c++11 /tmp/test.cpp -o /tmp/o

そして、次のエラーが表示されます。

/usr/include/c++/4.8/bits/move.h:176:11: error: use of deleted function ‘main()::__lambda0& main()::__lambda0::operator=(const main()::__lambda0&)’
   __a = _GLIBCXX_MOVE(__b);
       ^
/tmp/test.cpp:6:18: note: a lambda closure type has a deleted copy assignment operator

g++ -v

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.8.1-10ubuntu9' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9) 

ここで正確に何が起こっているのか興味がありますが、もっと重要なのは、これを機能させる方法を本当に知りたいということです.

4

4 に答える 4

8

ラムダ式の結果は移動構成可能ですが、必ずしも移動代入可能であるとは限らず、確実にコピー可能ではありません。std::reference_wrapper<decltype(comp)>コンパレータオブジェクトにa を使用して、問題を回避します。

typedef pair<int,float> ifpair;
auto comp = []( ifpair a,  ifpair b ) { return a.second > b.second; };
typedef priority_queue< ifpair , vector<ifpair>,
                        std::reference_wrapper<decltype( comp ) >> t_npq;
t_npq npq( std::ref(comp) );
t_npq empty( std::ref(comp) );
swap(npq , empty);

ラムダ式の完全な型情報は参照ラッパーによって保持されるため、これはクロージャーが空でなくても機能し、実行可能な場合は関数をインライン化できるはずです。

于 2013-12-23T21:00:43.120 に答える
1

ラムダは割り当てられません – 5.1.2/19:

ラムダ式に関連付けられたクロージャー型には、削除されたデフォルト コンストラクターと削除されたコピー代入演算子があります。

コンテナーのスワップもコンパレーターを割り当てたいので、それは機能しません。

ただし、最初にステートレス ラムダを関数ポインターに変換することで、簡単に機能させることができます。

bool (*p)(ifpair, ifpair) = [](ifpair a, ifpair b) { return a.second > b.second; };

今使用:

priority_queue<ifpair, vector<ifpair>, bool(*)(ifpair, ifpair)>

(関数 type: の typedef を導入して、どこでもusing comp_type = bool(iftype, iftype)使用することをお勧めしcomp_type *ます。)

于 2013-12-23T20:36:55.370 に答える
1

コンパイル エラーが示すように、ラムダ オブジェクトは代入できません。キューに別のタイプのファンクターを使用できますが、それでも labmda として記述できます。

  1. 使用std::function<bool(ifpair,ifpair)>: http://ideone.com/HZywoV

    しかし、これは の実装におけるいくつかの間接的なために (おそらく顕著な) オーバーヘッドを追加しますが、std::functionこれは標準ライブラリの実装とコンパイラの最適化に大きく依存していると思います。ただし、コードがどのように見えるかに関しては、最も良い解決策かもしれません。

  2. 関数ポインタを使用しますbool(*)(ifpair,ifpair): http://ideone.com/ZhFq3C

    std::functionこれは、現在のソリューションと比較してオーバーヘッドの影響を受けることはありません。ラムダコードに対してコンパイラの最適化が行われている可能性があるためです(つまり、残りのstd::queueコードにインライン化することで、たとえば2つのペアをコピーする必要がなくなります) )。ただし、関数ポインターの使用はかなり古風に見えます。

  3. http://ideone.com/9pcQFcのように単純なカスタム ファンクター クラスを使用します。

    template<typename Pair>
    struct GreaterBySecond {
        bool operator()(Pair a, Pair b) const {
            return a.second > b.second;
        }
    };
    

    これにより、上記で説明したすべてのオーバーヘッドが解消されます。性能を重視するならこちらがいいです。

于 2013-12-23T20:40:39.520 に答える
1

使ってみましたstd::functionか?

#include <queue>
#include <vector>
#include <functional>
using namespace std;
int main(){
    typedef pair<int,float> ifpair;
    std::function< bool ( ifpair, ifpair )> comp = []( ifpair a,  ifpair b ) { return a.second > b.second; };
    typedef priority_queue< ifpair , vector<ifpair>, decltype( comp ) > t_npq;
    t_npq npq( comp );
    //do something with npq. finish using it (without emptying it) and clear for next round
    t_npq empty( comp );
    swap(npq , empty);
}
于 2013-12-23T20:36:23.377 に答える