การแปลงโดยปริยายไม่ได้รับอนุญาตเมื่อส่งคืน


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
  • เมื่อการแสดงออกที่ใช้ในงบสวิทช์ (T2 เป็นประเภทที่สำคัญ);
  • เมื่อนิพจน์ถูกใช้ในคำสั่ง if หรือลูป (T2 คือบูล)

7
" โดยปริยายแปลงจะดำเนินการ"แต่operator bool()การเป็นstd::optional explicit
Jarod42

คำตอบ:


22

std::optionalไม่ได้มีสิ่งอำนวยความสะดวกใด ๆ boolสำหรับการแปลงไปโดยปริยาย (โดยboolทั่วไปการอนุญาตให้มีการแปลงโดยนัยถือว่าเป็นความคิดที่ไม่ดีเนื่องจากboolเป็นประเภทที่สมบูรณ์ดังนั้นสิ่งที่ต้องการint i = optรวบรวมและทำสิ่งที่ผิดทั้งหมด)

std::optional ไม่มี "แปลงบริบท" เพื่อ bool explicit operator bool()ความหมายของการที่มีลักษณะคล้ายกับผู้ประกอบการหล่อ: สิ่งนี้ไม่สามารถใช้สำหรับการแปลงโดยนัย มันใช้เฉพาะในบางสถานการณ์ที่ "บริบท" ที่คาดไว้เป็นบูลีนเช่นสภาพของคำสั่ง if

opt.has_value()สิ่งที่คุณต้องการคือ


4

จาก C ++ เอกสาร :

เมื่อวัตถุชนิดที่เป็นตัวเลือก <T>ถูกแปลงตามบริบทเป็นบูลการแปลงจะส่งกลับค่าจริงถ้าวัตถุมีค่าและเท็จถ้าไม่มีค่า

อ่านเกี่ยวกับการแปลงตามบริบทที่นี่ :

ในบริบทต่อไปนี้คาดว่าประเภทบูลและการแปลงโดยนัยจะดำเนินการถ้าการประกาศบูล t (e); มีรูปแบบที่ดี (นั่นคือฟังก์ชั่นการแปลงอย่างชัดเจนเช่น T :: โอเปอเรเตอร์บูล () const ที่ชัดเจน; การแสดงออกดังกล่าวถูกกล่าวว่าจะถูกแปลงเป็นบริบท

  • การควบคุมการแสดงออกของถ้าในขณะที่สำหรับ;
  • ตัวถูกดำเนินการของตัวดำเนินการเชิงตรรกะในตัว!, && และ ||;
  • ตัวถูกดำเนินการแรกของตัวดำเนินการแบบมีเงื่อนไขหรือไม่:;
  • เพรดิเคตในการประกาศ 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};
darune

3
@darune return {opt};จะไม่ทำงาน แต่return static_cast<bool>(opt);หรือreturn bool{opt};จะทำงาน อย่างไรก็ตามขอแนะนำให้ใช้has_valueฟังก์ชั่นสมาชิกเพราะมันแสดงให้เห็นชัดเจนว่าคุณต้องการทำอะไร
NutCracker

หรือreturn !!pot;แฮ็คที่มีชื่อเสียง( has_valueดีกว่า)
LF

1

นั่นเป็นเพราะการแปลงโดยนัยของ std :: ไม่สนับสนุน bool ไม่ได้รับการสนับสนุน: https://en.cppreference.com/w/cpp/utility/optional/operator_bool

ตัวดำเนินการ constexpr ชัดแจ้งบูล () const noexcept;

คุณต้องแปลงเป็นบูลอย่างชัดเจน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) - สำหรับ initializer ที่เป็นรายการนิพจน์วงเล็บหรือ braced-init-list (16.2) - สำหรับ new-initializer (7.6.2.7), (16.3) - ในนิพจน์ static_cast ( 7.6.1.8), (16.4) - ในการแปลงประเภทสัญกรณ์ทำงาน (7.6.1.3) และ (16.5) - ในรูปแบบ braced-init-list ของเงื่อนไขเรียกว่าการเริ่มต้นโดยตรง

อย่างไรก็ตามกรณีเหล่านี้จะไม่ใช้ฟังก์ชันการแปลง: [dcl.init] / p15

การเริ่มต้นที่เกิดขึ้นในรูปแบบ = ของวงเล็บปีกกา - หรือ - เท่ากับ - initializer หรือเงื่อนไข (8.5) เช่นเดียวกับในการผ่านการโต้แย้งฟังก์ชั่นกลับมาโยนข้อยกเว้น (14.2) จัดการข้อยกเว้น (14.4) และการเริ่มต้นสมาชิก (9.4.1) เรียกว่าการคัดลอกเริ่มต้น

ตัวอย่างในคำถามอยู่ภายใต้กรณีเริ่มต้นการคัดลอกและไม่ใช้ฟังก์ชันการแปลงของทางเลือก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.