戻り時に暗黙的な変換は許可されていません


21
#include <optional>

bool f() {
  std::optional<int> opt;
  return opt;
}

コンパイルしません: 'return': cannot convert from 'std::optional<int>' to 'bool'

参考資料を参考にして説明を探したのですが、大丈夫なので読んでみました。

暗黙的な変換は、あるタイプT1の式がそのタイプを受け入れないが他のタイプT2を受け入れるコンテキストで使用される場合は常に実行されます。特に:

  • T2をパラメーターとして宣言された関数を呼び出すときに、式が引数として使用される場合。
  • 式がT2を期待する演算子でオペランドとして使用される場合。
  • T2を返す関数のreturnステートメントを含む、T2型の新しいオブジェクトを初期化するとき;
  • 式がswitchステートメントで使用されている場合(T2は整数型)。
  • 式がifステートメントまたはループで使用される場合(T2はブール値)。

7
暗黙の変換が実行されます」operator bool()、のstd::optional場合explicit
Jarod42

回答:


22

std::optional暗黙的にに変換する機能はありませんbool。(への暗黙の変換を許可することboolは、一般的には悪い考えと考えられます。なぜなら、boolは整数型なので、int i = optコンパイルして完全に間違った動作をするからです。

std::optional には、ブールへの「コンテキスト変換」があり、その定義はキャスト演算子に似ていますexplicit operator bool()。これは暗黙的な変換には使用できません。ifステートメントの条件のように、予期される「コンテキスト」がブール値である特定の状況にのみ適用されます。

あなたが欲しいのはopt.has_value()です。


4

C ++ ドキュメントから:

optional <T>のオブジェクトがコンテキスト的にboolに変換されると、オブジェクトに値が含まれている場合は変換によってtrueが返され、値が含まれていない場合はfalseが返されます。

ここでコンテキスト変換についてお読みください

次のコンテキストでは、bool型が想定されており、宣言bool t(e);の場合、暗黙的な変換が実行されます。整形式です(つまり、明示的なT :: operator bool()const;などの明示的な変換関数が考慮されます)。そのような式eは、文脈的にブールに変換されると言われています。

  • if、while、forの制御式。
  • 組み込み論理演算子!、&&および||;のオペランド
  • 条件演算子の最初のオペランド?:;
  • static_assert宣言の述語。
  • noexcept指定子内の式。
  • 明示的な指定子での式。

次のハックを実行できます。

bool f() {
    std::optional<int> opt;
    return opt || false;
}

組み込み論理演算子の場合にコンテキスト変換が行われますが、コンテキスト変換にはreturnステートメントが含まstd::optionalれておら、それ自体には暗黙的なへの変換がありませbool

したがって、以下を使用するのが最善std::optional<T>::has_valueです。

bool f() {
    std::optional<int> opt;
    return opt.has_value();
}

どうreturn {opt}ですか?またはreturn bool{opt};
だるね

3
@darune return {opt};は機能しませんがreturn static_cast<bool>(opt);return bool{opt};機能します。ただし、has_valueメンバー関数を使用することをお勧めします。これは、実行したいことの明確な意図を実際に示しているためです
NutCracker

または有名なreturn !!pot;ハック(has_value優れています)
LF

1

これは、std :: optionalからboolへの暗黙のカバーがサポートされていないためです。https://en.cppreference.com/w/cpp/utility/optional/operator_bool

constexpr明示的演算子bool()const noexcept;

明示的にboolに変換するbool(opt)か、単にopt.has_value()代わりに使用する必要があります。


bool {opt}も同様に機能し、bool(opt)よりも優先する必要があります
darune

1

これは実際には暗黙的な変換ではなく、初期化のタイプです。

オプションには、明示的な変換関数があります。

explicit operator bool() const; 

N4849から[class.conv.fct] / p2

変換関数は明示的(9.2.2)である場合があります。その場合、それは直接初期化のユーザー定義の変換としてのみ考慮されます。

上記は、これらのケースが変換関数を使用することを意味します:[dcl.init] / p16

発生する初期化(16.1)—括弧で囲まれた式リストまたは括弧付き初期リストである初期化子の場合(16.2)—新規初期化子(7.6.2.7)の場合(16.3)— static_cast式内( 7.6.1.8)、(16.4)—関数表記タイプ変換(7.6.1.3)、および(16.5)—条件の括弧付き初期リスト形式では、直接初期化と呼ばれます。

ただし、これらのケースでは変換関数を使用しません:[dcl.init] / p15

=形式の波括弧またはイコライザーまたは条件(8.5)のほか、引数の受け渡し、関数の戻り、例外のスロー(14.2)、例外の処理(14.4)、およびメンバーの初期化で発生する初期化(9.4.1)は、コピー初期化と呼ばれます。

問題の例は、コピーの初期化のケースに該当し、オプションの変換関数を使用していません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.