?
{}
は、代入の右側にあるoperator=
の非明示的なコンストラクタを呼び出すことができます。
使用可能operator=
過負荷である:
tuple& operator=(const tuple& other);
tuple& operator=(tuple&& other);
template< class... UTypes >
tuple& operator=(const tuple<UTypes...>& other);
template< class... UTypes >
tuple& operator=(tuple<UTypes...>&& other);
template< class U1, class U2 >
tuple& operator=(const pair<U1,U2>& p);
template< class U1, class U2 >
tuple& operator=(pair<U1,U2>&& p);
template
オペレータのオーバーロードは、{}
(注:これはC++ 17に変更してもよい)からその種類を推測することができないまま、:
tuple& operator=(const tuple& other);
tuple& operator=(tuple&& other);
この場合、tuple
はstd::tuple<int&, int&>
です。
tuple<Ts...>
のタプルコンストラクタは、完全な要素順構築がexplicit(そのリストの#3)です。 {}
は明示的なコンストラクタを呼び出さない。
条件付き非明示的コンストラクタは、Ts const&...
をとります。 Ts
がコピー不可能であり、int&
がコピー不可能な場合は存在しません。
したがって、{int&, int&}
から構築する実行可能なタイプはなく、オーバーロードの解決に失敗します。
標準ではこれが解決されないのはなぜですか?さて、私たちは自分でそれをすることができます!
この問題を解決するには、タイプがすべて参照の場合にのみ、tuple
に特別な(Ts...)
非明示的なコンストラクタを追加する必要があります。
私たちはおもちゃのタプル書く場合:
struct toy {
std::tuple<int&, int&> data;
toy(int& a, int& b):data(a,b) {} // note, non-explicit!
};
toy toy_tie(int& a, int& b) { return {a,b}; }
と、それを使用し、あなたはその
std::tie(a, b) = {b, a};
コンパイルと実行に気付くでしょう。
a%b
がint&
にバインドすることはできませんしかし、
std::tie(a, b) = { b, a % b };
は、しません。
我々は、次いで、toy
を増強することができる:(+特別なメンバ関数をデフォルトtemplate<class...>
は、それが必要として、それは特別なメンバ関数よりも低い優先度を有している保証する。)
template<class...>
toy& operator=(std::tuple<int, int> o) {
data = o;
return *this;
}
。
これにより、割り当て元は{int,int}
になります。私たちはそれを実行し、間違った結果を得る。 5,20
のgcdは20
です。何が悪かったのか?参照にバインドされa
とb
の両方で
toy_tie(a, b) = std::tie(b, a);
安全なコードではありません、それは
toy_tie(a, b) = { b, a };
が何をするかです。
要するに、この権利を行うことは難しいです。この場合、安全のために割り当てようとする前に、のコピーを右側に置く必要があります。コピーを取る時期とそうでないことを知っていることもやりにくいです。
この作業を暗黙的に行うと、エラーが発生しやすくなります。ある意味では、それがうまくいかず、(可能な限り)それを修正することは悪い考えのように見えます。
live example。
素晴らしい説明..私はPythonの複数の割り当て(例えばa、b = b、a%b)の影響を受けましたが、これは安全に(Pythonのように)毎回コピーを取る必要があります。 –