Konversi tersirat tidak diizinkan untuk dikembalikan

21
#include <optional>

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

Tidak mengkompilasi: 'return': cannot convert from 'std::optional<int>' to 'bool'

Referensi konsultasi Saya akan berpikir untuk menemukan penjelasan, tetapi saya membacanya sebagaimana mestinya ok.

Konversi tersirat dilakukan setiap kali ekspresi dari beberapa tipe T1 digunakan dalam konteks yang tidak menerima tipe itu, tetapi menerima beberapa tipe T2 lainnya; khususnya:

  • ketika ekspresi digunakan sebagai argumen saat memanggil fungsi yang dideklarasikan dengan T2 sebagai parameter;
  • ketika ekspresi digunakan sebagai operan dengan operator yang mengharapkan T2;
  • saat menginisialisasi objek baru tipe T2, termasuk pernyataan pengembalian dalam fungsi mengembalikan T2;
  • ketika ekspresi digunakan dalam pernyataan switch (T2 adalah tipe integral);
  • ketika ekspresi digunakan dalam pernyataan if atau loop (T2 bool).
sayang
sumber
7
" Konversi tersirat dilakukan" , tetapi operator bool()dari std::optionaladalah explicit.
Jarod42

Jawaban:

22

std::optionaltidak memiliki fasilitas untuk melakukan konversi secara implisit bool. (Mengizinkan konversi implisit ke boolumumnya dianggap sebagai ide yang buruk, karena boolmerupakan tipe integral sehingga sesuatu seperti int i = optakan mengkompilasi dan melakukan hal yang sepenuhnya salah.)

std::optional tidak memiliki "konversi kontekstual" untuk bool, definisi yang terlihat mirip dengan operator cor: explicit operator bool(). Ini tidak dapat digunakan untuk konversi tersirat; itu hanya berlaku dalam situasi spesifik tertentu di mana "konteks" yang diharapkan adalah yang boolean, seperti kondisi pernyataan-if.

Yang Anda inginkan adalah opt.has_value().

Sneftel
sumber
4

Dari dokumen C ++ :

Ketika objek tipe opsional <T> secara kontekstual dikonversi menjadi bool, konversi mengembalikan true jika objek berisi nilai dan false jika tidak mengandung nilai.

Baca tentang konversi kontekstual di sini :

Dalam konteks berikut, tipe bool diharapkan dan konversi implisit dilakukan jika deklarasi bool t (e); terbentuk dengan baik (yaitu, fungsi konversi eksplisit seperti eksplisit T :: operator bool () const; dipertimbangkan). Ungkapan seperti itu dikatakan dikonversi secara kontekstual menjadi bool.

  • ekspresi mengendalikan jika, sementara, untuk;
  • operan dari operator logis bawaan!, && dan ||;
  • operan pertama dari operator kondisional?:;
  • predikat dalam deklarasi static_assert;
  • ekspresi dalam specifier noexcept;
  • ekspresi dalam specifier eksplisit;

Anda dapat melakukan retasan berikut:

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

karena konversi kontekstual terjadi dalam kasus operator logis bawaan, tetapi konversi kontekstual tidak menyertakan returnpernyataan dan std::optionaldengan sendirinya tidak memiliki konversi implisit ke bool.

Karena itu, yang terbaik adalah menggunakan std::optional<T>::has_value:

bool f() {
    std::optional<int> opt;
    return opt.has_value();
}
Alat pemecah buah keras
sumber
bagaimana return {opt}? ataureturn bool{opt};
darune
3
@ Darune return {opt};tidak akan berfungsi tetapi return static_cast<bool>(opt);atau return bool{opt};akan bekerja. Namun, disarankan untuk menggunakan has_valuefungsi anggota karena itu benar-benar menunjukkan niat yang jelas tentang apa yang ingin Anda lakukan
NutCracker
Atau return !!pot;hack terkenal ( has_valuelebih baik)
LF
1

Itu karena penutup implisit std :: opsional untuk bool tidak didukung: https://en.cppreference.com/w/cpp/utility/optional/operator_bool

constexpr operator eksplisit bool () const noexcept;

Anda harus secara eksplisit mengkonversi ke bool sebagai bool(opt)atau hanya menggunakan opt.has_value()saja.

theWiseBro
sumber
bool {opt} berfungsi dengan baik dan lebih disukai daripada bool (opt)
darune
1

Ini bukan tentang konversi implisit, ini tentang jenis inisialisasi.

Apa yang opsional miliki adalah fungsi konversi eksplisit, yaitu

explicit operator bool() const; 

Dari N4849 [class.conv.fct] / p2

Fungsi konversi mungkin eksplisit (9.2.2), dalam hal ini hanya dianggap sebagai konversi yang ditentukan pengguna untuk inisialisasi langsung.

Di atas berarti bahwa kasus-kasus ini akan menggunakan fungsi konversi: [dcl.init] / p16

Inisialisasi yang terjadi (16.1) - untuk penginisialisasi yang merupakan daftar ekspresi terkurung atau daftar yang di-brace-init, (16.2) - untuk penginisialisasi baru (7.6.2.7), (16.3) - dalam ekspresi static_cast ( 7.6.1.8), (16.4) - dalam konversi tipe notasi fungsional (7.6.1.3), dan (16.5) - dalam bentuk daftar kondisi yang dinamakan brace-init disebut kondisi yang disebut inisialisasi langsung.

Namun, case-case ini tidak akan menggunakan fungsi konversi: [dcl.init] / p15

Inisialisasi yang terjadi dalam bentuk = inisialisasi brace-atau-sama-sama atau kondisi (8.5), serta dalam melewati argumen, fungsi kembali, melemparkan pengecualian (14.2), menangani pengecualian (14.4), dan inisialisasi anggota (9.4.1), disebut inisialisasi salin.

Contoh dalam pertanyaan termasuk dalam kasus inisialisasi salinan dan tidak menggunakan fungsi konversi opsional.

Trixie
sumber