std :: swapがClang / Winのvector <bool>要素で機能しないのはなぜですか?


14

私はこのようなコードを持っています:

#include <vector>
#include <utility>

int main()
{
   std::vector<bool> vb{true, false};
   std::swap(vb[0], vb[1]);
}

vector<bool>脇見の健全性についての議論は、これはうまく機能していました:

  • Mac用のClang
  • Visual Studio for Windows
  • Linux用GCC

次に、WindowsでClangを使用してビルドしようとすると、次のエラー(要約)が表示されました。

error: no matching function for call to 'swap'
                                std::swap(vb[0], vb[1]);
                                ^~~~~~~~~

note: candidate function [with _Ty = std::_Vb_reference<std::_Wrap_alloc<std::allocator<unsigned int> > >, $1 = void] not viable: expects an l-value for 1st argument
inline void swap(_Ty& _Left, _Ty& _Right) _NOEXCEPT_COND(is_nothrow_move_constructible_v<_Ty>&&

結果は実装によって異なることに驚いています。

WindowsのClangで動作しないのはなぜですか?


だから私は必要な説明が必要だと思います:operator[]左辺値の結果ですか?std::swap右辺値とx値を操作できますか?
Mgetz

@Mgetzはい。いいえ。この質問は先日プライベートで「本当の意味で」尋ねられましたが、答えは「Clang / Winは壊れていません。コードはずっと壊れていましたが、メインストリームのツールチェーンコンボはあなたに話そうとはしませんでした。"ここにそれを書きます:P
オービットのライトネスレース

2
参考までに、これはVS 2019では/permissive-(適合性)でコンパイルされません。通常、これはとにかく使用する必要があります;)
ChrisMM

1
@ChrisMM確かに!適合モードオフはパズルの一部でした。(それを調べる前にそれを知りませんでしたが!)そして私の答えはそれを指摘しています:P
オービットでの軽さの

回答:


15

標準では、上でコンパイルするために、これを必要としない任意のツールチェーン!

まずvector<bool>奇妙なことを思い出してください。添え字を付けるとstd::vector<bool>::reference、実際のではなくと呼ばれるプロキシタイプの一時オブジェクトが得られますbool&

エラーメッセージはconst、一般的なtemplate <typename T> std::swap(T& lhs, T& rhs)実装では、この一時変数を非左辺値参照にバインドできないことを示しています。

拡張機能!

しかし、それはのlibstdc ++があることが判明し、過負荷を定義するためにstd::swap(std::vector<bool>::reference, std::vector<bool>::reference)ことがわかりますが、これは標準に対する拡張機能です(または、そこにある場合は、その証拠を見つけることができません)。

libc ++ もこれを行います

あなたがまだ使用しているVisual Studio stdlib実装はそうはない思いますが、傷害に侮辱を加えるために、VSの一時値をVSの左辺値参照バインドできます(準拠モードを使用している場合を除く)。std::swapより厳密なClangコンパイラをVSコンパイラに置き換えるまで、標準の「汎用」関数は機能します。

その結果、機能する3つのツールチェーンすべての拡張機能に依存してきました。WindowsのClangの組み合わせは、厳密なコンプライアンスを実際に示している唯一のものです。

(私の意見では、これらの3つのツールチェーンはこれを診断しているはずなので、移植性のないコードをずっと出荷することはありませんでした。😊)

今何?

あなた自身の専門分野を追加したくすることができるstd::swapとしstd::vector<bool>::referenceていますが、標準的なタイプのためにこれを行うには許可されていません。実際、libstdc ++およびlibc ++が拡張機能として追加することを選択したオーバーロードと競合します。

したがって、移植可能で準拠するには、コードを変更する必要があります

おそらく古き良きもの:

const bool temp = vb[0];
vb[0] = vb[1];
vb[1] = temp;

または、まさにあなたが望んだことをする特別な静的メンバー関数を利用してください

std::vector<bool>::swap(vb[0], vb[1]);

次のようにスペルも可能です。

vb.swap(vb[0], vb[1]);

については、それは彼らがそうすることを許可されている AFAIKに想定されていません。準拠コードを壊さない限り、実装を拡張して、壊れたコードを「OK」にすることができます。
NathanOliver

@ NathanOliver-ReinstateMonicaさて、わかりました。彼らは少なくともそのようなものの使用を診断する必要はありませんか?eel.is/c++draft/intro.compliance#8
オービットの

@LightnessRaceswithMonicaこの拡張を禁止する言語はありますか?
Mgetz

私がいることを答えることができないので@Mgetz申し訳ありませんが、私はすべての現存の言語に精通していないよ
軌道上での明度レース

このドキュメントに従って不適切な形式の拡張機能を使用するかどうかはわかりません。彼らはaをとるオーバーロードを追加しましたstd::vector<bool>::reference。私にとっては、のようなものを使用char * foo = "bar";すると診断が必要になるように聞こえます。
NathanOliver
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.