最終更新日時(UTC):
が更新

履歴 編集

ポインタからboolへの変換を縮小変換とする(C++20)

概要

ポインタ型(メンバポインタも含む)からbool型への変換が、縮小変換として規定されるようになる。

struct A {
  bool b;
};

int main() {
  int *p = nullptr;

  A a{p}; // NG、{}初期化では縮小変換は許可されない
}

これはC++17に対する欠陥報告であるため、実装済みのコンパイラにおいてはC++17モード(-std=c++17を指定した場合など)でコンパイルした場合にも適用される。

この機能が必要になった背景・経緯

C++17で導入されたstd::variantには当初、const char*からboolへの暗黙変換によって意図しない構築がなされるバグがあった。

std::variant<std::string, bool> x = "abc";  // boolを保持して構築されてしまう

この他にも構築・代入時に縮小変換が行われてしまう事から同様の問題があり、それはC++20においてP0608R3によって解決された。そこでは、構築・代入時の縮小変換を禁止するとともに、boolに変換可能な型をboolに変換することを禁止することで問題に対処していた。

しかしそれによって、boolに変換可能なユーザー定義型をbool値として構築・代入することができなくなった。

std::bitset<4> b("0101");
std::variant<bool, int> v = b[1]; // intを保持して構築されてしまう

std::bitsetの非constoperator[]bool型へ暗黙変換可能なプロクシオブジェクトを返す。

std::variantの構築・代入時に縮小変換が起こることを検出して防止することはライブラリレベルで可能だったが、ポインタ型からboolへの変換を縮小変換として扱うということはライブラリレベルでは実装できなかったためboolへの変換全体を禁止せざるを得ず、このような問題が発生していた。

これらの問題の解決のために、ポインタ型からbool型への変換は縮小変換であると規定することになった。これによって、std::variantの構築・代入時のポインタ型からbool型への変換は縮小変換の一種として検出され禁止されるようになり、上記のコードは意図どおりに動作するようになる。

std::variant<std::string, bool> x = "abc";  // std::stringを保持して構築

std::bitset<4> b("0101");
std::variant<bool, int> v = b[1]; // boolを保持して構築

{}初期化では縮小変換が禁止されているためこれは破壊的変更となるが、そのような変換は多くの場合バグの可能性が高いこと、MSVCは非リテラルのポインタからboolへの変換を縮小変換として扱っていたことなどから、影響は少なくメリットの方が大きいと判断されたようだ。

関連項目

参照