İade sırasında örtük dönüştürmeye izin verilmiyor


21
#include <optional>

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

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

Referansa danışmak Bir açıklama bulmayı düşünürdüm, ama olması gerektiği gibi okudum.

Örtük dönüşümler, T1 türünde bir ifade, bu türü kabul etmeyen, ancak başka bir T2 türünü kabul eden bağlamda kullanıldığında gerçekleştirilir; özellikle:

  • parametre olarak T2 ile bildirilen bir işlevi çağırırken ifade argüman olarak kullanıldığında;
  • ifade T2'yi bekleyen bir işleçle birlikte işlenen olarak kullanıldığında;
  • T2 döndüren bir işlevde return ifadesi de dahil olmak üzere T2 türünde yeni bir nesne başlatırken;
  • ifade bir switch ifadesinde kullanıldığında (T2 integral tiptir);
  • ifade bir if ifadesinde veya döngüde kullanıldığında (T2 bool'dur).

7
" Örtülü dönüşümler yapılır" ama operator bool()bir std::optionalolduğunu explicit.
Jarod42

Yanıtlar:


22

std::optionaldolaylı olarak dönüştürmek için herhangi bir olanağı yok bool. (Örtük dönüşümlere izin vermek boolgenellikle kötü bir fikir olarak kabul edilir, çünkü boolayrılmaz bir tür olduğundan , böyle bir şey int i = optderlenir ve tamamen yanlış bir şey yapar.)

std::optional gelmez bir döküm operatörü benzer tanım olan bool için bir "içeriksel dönüşümü" vardır:explicit operator bool() . Bu, örtük dönüşümler için kullanılamaz; yalnızca beklenen "bağlamın" bir if ifadesinin durumu gibi bir boole olduğu belirli belirli durumlarda geçerlidir.

Ne istiyorsun opt.has_value().


4

C ++ belgelerinden :

Tip bir amacı zaman isteğe bağlı <t> olan içeriğe dayalı dönüştürülmüş bool için bir değer içeriyorsa, gerçek dönüşüm döner nesnenin bir değeri ve yanlış içeriyorsa.

Bağlamsal dönüşümler hakkında buradan bilgi edinin :

Aşağıdaki bağlamlarda, bool türü beklenir ve bildirim bool t (e) ise örtük dönüştürme gerçekleştirilir; iyi biçimlendirilmiş (yani, açık T :: operator bool () const gibi açık bir dönüştürme işlevi dikkate alınır). Bu tür bir e ifadesinin bağlamsal olarak boole dönüştürüldüğü söylenir.

  • için if, while, kontrol ifadesi;
  • yerleşik mantıksal operatörlerin işlenenleri! && ve ||;
  • koşullu operatörün ilk işleneni?:;
  • static_assert bildirimindeki yüklem;
  • istisna olmayan bir tanımlayıcıdaki ifade;
  • açık bir tanımlayıcıdaki ifade;

Aşağıdaki hack'i yapabilirsiniz:

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

bağlamsal dönüşüm yok mantıksal operatörler yerleşik, ancak içeriksel dönüşüm durumunda olur çünkü değil şunlardır returnifadeleri ve std::optionalyok tek başına değil örtülü dönüşüm varbool .

Bu nedenle, aşağıdakileri kullanmak en iyisi olacaktır std::optional<T>::has_value:

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

Ne hakkında return {opt}? veyareturn bool{opt};
darune

3
@darune return {opt};işe yaramaz ama return static_cast<bool>(opt);ya return bool{opt};çalışacak. Bununla birlikte, has_valueüye işlevini kullanmanız önerilir çünkü gerçekten ne yapmak istediğinizin açık niyetini gösterir
NutCracker

Veya ünlü return !!pot;kesmek ( has_valuedaha iyi)
LF


1

Bu aslında örtük dönüşümle ilgili değil, bu başlatma türüyle ilgilidir.

İsteğe bağlı olan, açık bir dönüştürme işlevidir.

explicit operator bool() const; 

N4849'dan [class.conv.fct] / p2

Bir dönüştürme işlevi açık (9.2.2) olabilir, bu durumda yalnızca doğrudan başlatma için kullanıcı tanımlı bir dönüşüm olarak kabul edilir.

Yukarıdaki durumlar, bu durumlarda dönüştürme işlevini kullanacağı anlamına gelir: [dcl.init] / p16

Statik_anyanlı ifadede (16.1) - parantez içine alınmış bir ifade listesi veya hazırlanmış bir init listesi olan bir başlatıcı için (16.2) - yeni başlatıcı (7.6.2.7), (16.3) için başlatma (16.2) 7.6.1.8), (16.4) - fonksiyonel gösterim tipi dönüşümünde (7.6.1.3) ve (16.5) - bir koşulun hazır başlangıç ​​listesi biçiminde doğrudan başlatma olarak adlandırılır.

Ancak, bu durumlar dönüştürme işlevini kullanmayacaktır: [dcl.init] / p15

Bir küme ayracı veya eşit başlatıcı veya koşul (8.5) biçiminde ve ayrıca argüman iletme, işlev dönüşü, bir istisna atma (14.2), bir istisna işleme (14.4) ve üye başlatma işlemlerinde gerçekleşen başlatma (9.4.1), kopya başlatma olarak adlandırılır.

Sorudaki örnek, kopyalama başlatma durumunun altına girer ve isteğe bağlı dönüşüm işlevini kullanmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.