次のように、std::pair 内にコピー不可能な (ただし移動可能な) オブジェクトを格納しようとしています。
#include <utility>
struct S
{
S();
private:
S(const S&);
S& operator=(const S&);
};
int main()
{
std::pair<int, S> p{0, S()};
return 0;
}
しかし、gcc 4.6 で次のコンパイラ エラーが発生します。
In file included from include/c++/4.6.0/bits/move.h:53:0,
from include/c++/4.6.0/bits/stl_pair.h:60,
include/c++/4.6.0/utility:71,
from src/test.cpp:1:
include/c++/4.6.0/type_traits: In instantiation of 'const bool std::__is_convertible_helper<S, S, false>::__value':
include/c++/4.6.0/type_traits:789:12: instantiated from 'std::is_convertible<S, S>'
src/test.cpp:13:31: instantiated from here
src/test.cpp:7:5: error: 'S::S(const S&)' is private
include/c++/4.6.0/type_traits:782:68: error: within this context
In file included from include/c++/4.6.0/utility:71:0,
from src/test.cpp:1:
src/test.cpp: In constructor 'std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int, <template-parameter-2-2> = void, _T1 = int, _T2 = S]':
src/test.cpp:13:31: instantiated from here
src/test.cpp:7:5: error: 'S::S(const S&)' is private
include/c++/4.6.0/bits/stl_pair.h:121:45: error: within this context
std::pair<_T1, _T2>::pair(_U1&&, const _T2&)
コンパイラーがコンストラクターを呼び出そうとしているようですが、もちろん問題があります。std::pair<_T1, _T2>::pair(_U1&&, _U2&&)
代わりにコンパイラがコンストラクタを呼び出すべきではありませんか? ここで何が起こっているのですか?
編集:わかりました、明示的な移動コンストラクターを提供すると問題が解決することは理解していますが、まだ少し混乱しています。
boost::noncopyable
独自のプライベート コピー コンストラクターを宣言するのではなく、から継承することにより、クラスをコピー不可にするとします。
以下は正常に動作し、ムーブ コンストラクターが暗黙的に生成されることを示唆しています。
#include <boost/noncopyable.hpp>
struct S : boost::noncopyable
{
};
void f(S&&)
{
}
int main()
{
f(S());
return 0;
}
ただし、std::pair
それでも機能しません。
#include <utility>
#include <boost/noncopyable.hpp>
struct S : boost::noncopyable
{
};
int main()
{
std::pair<int, S> p{0, S()};
return 0;
}
エラー:
In file included from include/c++/4.6.0/utility:71:0,
from src/test.cpp:1:
/include/c++/4.6.0/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int, <template-parameter-2-2> = void, _T1 = int, _T2 = S]':
src/test.cpp:16:31: instantiated from here
/include/c++/4.6.0/bits/stl_pair.h:121:45: error: use of deleted function 'S::S(const S&)'
src/test.cpp:4:8: error: 'S::S(const S&)' is implicitly deleted because the default definition would be ill-formed:
boost/boost/noncopyable.hpp:27:7: error: 'boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable&)' is private
src/test.cpp:4:8: error: within this context
さらに、= default
-ed デフォルト コンストラクターとムーブ コンストラクターを追加しても役に立ちません。
#include <utility>
#include <boost/noncopyable.hpp>
struct S : boost::noncopyable
{
S() = default;
S(S&&) = default;
};
int main()
{
std::pair<int, S> p{0, S()};
return 0;
}
同じエラーが発生します。move コンストラクターの定義を自分で明示的に指定する必要があります。これは、クラスに多くのメンバーがある場合に面倒です。
#include <utility>
#include <boost/noncopyable.hpp>
struct S : boost::noncopyable
{
S() = default;
S(S&&) {}
};
int main()
{
std::pair<int, S> p{0, S()};
return 0;
}