私の問題を示すために、コンパイルされない次の単純なプログラムを考えてみましょう。
#include <boost/noncopyable.hpp>
#include <unordered_map>
class foo : boost::noncopyable { };
int main()
{
std::unordered_map<int, foo> m;
auto & element = m[0];
return 0;
}
現在のバージョンのブースト (1.52) を使用すると、Visual Studio 2012 は次のエラーを返します:
cannot access private member declared in class 'boost::noncopyable_::noncopyable
.
std::unordered_map の演算子 [] は、指定されたキーにある要素への参照を返します。これは一見うまくいくように見えます。要素のコピーではなく、要素への参照を要求しました。
この問題についての私の理解は次のとおりです (しばらく C++ を使用していないため、これは間違っている可能性があります)。キーが見つからない場合、unordered_map は新しい要素を作成し、新しい要素への参照を返します。boost::noncopyable は (プライベート) コピー コンストラクターを定義しますが、移動コンストラクターは定義しないため、移動コンストラクターはコンパイラによって生成されません。その operator[] では、std::unordered_map は std::move を使用しますが、boost::noncopyable は移動コンストラクターを定義していないため、コピー コンストラクターにフォールバックします。コピー コンストラクターはプライベートであるため、コンパイルは失敗します。
この投稿を促したのは、boost::noncopyable を継承する boost::signal2::signal の unordered_map を作成しようとしているからです。ブースト ライブラリをハッキングする以外に、簡単な回避策はありますか? 信号を unique_ptr にラップすることはオプションですが、ここで何か間違ったことをしている可能性があります。
アップデート:
投稿が早すぎたかも!boost::noncopyable のサブクラスを unordered_map に追加することは不可能のようです。Insert、operator[]、および emplace はすべて、コピー コンストラクター (非公開) または移動操作 (boost::noncopyable には存在しません) のいずれかを使用します。私には、これが大きな制限のように思えます。boost::noncopyable オブジェクトを含む unordered_map を作成することさえ可能ですか? 私は明示的にそれらをコピーしようとしているわけではありません- unordered_map 内で全寿命を過ごすようにしたいのです。