web-dev-qa-db-ja.com

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

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

#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で動作しないのはなぜですか?

標準では、anyツールチェーンでコンパイルするためにこれを必要としません!

最初に、_vector<bool>_は奇妙で、添字を付けると、実際の_std::vector<bool>::reference_ではなく、_bool&_というプロキシタイプの一時オブジェクトが得られることを思い出してください。

エラーメッセージは、この_temporaryをジェネリックtemplate <typename T> std::swap(T& lhs, T& rhs)実装の非const lvalue参照にバインドできないことを示しています。

拡張機能!

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

libc ++ これも行います

あなたがまだ使用しているVisual Studio stdlib実装は使用しないが、その後、傷害に侮辱を追加する 一時ファイルを左辺値参照 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]);
_