2017-05-20 29 views
11

std::variant Benim int, std::string veya bool numaralı belgeleri içerebilir.Varyasyonum neden bir std :: string'i bir boole dönüştürüyor?

var = "this is my string" olarak verilen bir dize ile beslemek istediğimde, bir dizeye değil bool dönüştürülür. Açık bir şekilde bildirirseniz, var = std::string("this is my string") çalışır. Neden böyle ve bundan kaçınmak için yapabileceğim bir şey var mı? Benim kod kullanıcıların açıkça string s yapmak olmayabilir yana

#include <string> 
#include <variant> 
#include <iostream> 

int main() 
{ 
    using var = std::variant<std::monostate, int, std::string, bool>; 

    var contains_nothing;  
    var contains_int = 5; 
    var contains_string = "hello"; 
    var contains_expl_string = std::string("explicit hello"); 
    var contains_bool = false; 

    auto visitor = [](auto&& arg){ 
      using T = std::decay_t<decltype(arg)>; 
      if constexpr (std::is_same<T, std::monostate>()) 
       std::cout<<"nothing\n"; 
      else if constexpr (std::is_same<T, int>()) 
       std::cout<<"int: "<<arg<<"\n"; 
      else if constexpr (std::is_same<T, std::string>()) 
       std::cout<<"string: "<<arg<<"\n"; 
      else if constexpr (std::is_same<T, bool>()) 
       std::cout<<"bool: "<<arg<<"\n"; 
      else 
       std::cout<<"Visitor is not exhaustive\n"; 
     }; 

    std::visit(visitor, contains_nothing);  // nothing 
    std::visit(visitor, contains_int);   // int: 5 
    std::visit(visitor, contains_string);  // bool: 1 
    std::visit(visitor, contains_expl_string); // string: explicit hello 
    std::visit(visitor, contains_bool);   // bool: 0  
} 

DÜZENLEME , bunu yakalamak ister. Aksi halde bir hata kaynağı olur. Bir char*'un iletilip geçirilmediğini kontrol eden şablon yardımcısı işlevi yaptım ve eğer öyleyse, bir std :: dizesi oluşturur. İyi çalışıyor. Bu daha basit hale getirmek için Yardım takdir! make_var tartışmasız çağrıldığında

varsayılan parametre/türü olarak std::monostate ilan ederek DÜZENLEME 2 , hatta çalışır.

#include <string> 
#include <variant> 
#include <iostream> 

using var = std::variant<std::monostate, int, std::string, bool>; 

template<typename T = std::monostate> 
var make_var(T value = std::monostate()) 
{ 
    if constexpr (std::is_same<typename std::remove_const<typename std::decay<T>::type>::type, const char*>()) 
     return std::string(value); 
    return value; 
} 

int main() 
{ 
    auto contains_nothing = make_var();  
    auto contains_int = make_var(3); 
    auto contains_string = make_var("hello"); 
    auto contains_expl_string = make_var(std::string("excplicit hello")); 
    var contains_bool = make_var(false); 

    auto visitor = [](auto&& arg){ 
      using T = std::decay_t<decltype(arg)>; 
      if constexpr (std::is_same<T, std::monostate>()) 
       std::cout<<"nothing\n"; 
      else if constexpr (std::is_same<T, int>()) 
       std::cout<<"int: "<<arg<<"\n"; 
      else if constexpr (std::is_same<T, std::string>()) 
       std::cout<<"string: "<<arg<<"\n"; 
      else if constexpr (std::is_same<T, bool>()) 
       std::cout<<"bool: "<<arg<<"\n"; 
      else 
       std::cout<<"Visitor is not exhaustive\n"; 
     }; 

    std::visit(visitor, contains_nothing); 
    std::visit(visitor, contains_int); 
    std::visit(visitor, contains_string); 
    std::visit(visitor, contains_expl_string); 
    std::visit(visitor, contains_bool);  
} 
+2

, neden 'std :: tercih edilmesi string' gerektiğini edilir sormak başka soru 'bool'? Her ikisi de dizi bozulması ve tür dönüşümü gerektirir. – juanchopanza

+1

http://stackoverflow.com/questions/44021989/implicit-cast-from-const-string-to-bool adresindeki güzel cevabımı özellikle bir şablon kullanarak geçici çözümüm ;-). Ancak Angew'in kullanıcı tarafından tanımlanmış bir edebi (aşağıda) kullanımı cuter'dir. – Bathsheba

+0

kısa cevap: değil, çünkü bu bir "std :: string" vermedi. –

cevap

27

"hello" tipi const char * dönüşür ki, const char [6] olup. const char * - bool arasındaki dönüşüm, dahili bir dönüşümdür; const char * - std::string arasındaki dönüşüm, kullanıcı tanımlı bir dönüşümdür;

sen C++> = 14 kullandığınızdan, sen göstermek için hazır bilgi eki s kullanabileceği bir std::string literal:

using namespace std::string_literals; 

var contains_string = "hello"s; 
+1

Neden "bool" yerine "int" türünü seçmedi? – skypjack

+15

@skypjack C++ 'da int' dönüşümü için dolaylı bir işaretleyici olmadığından. – Angew

+0

Gerçekten de mantıklı. Teşekkür ederim.:-) – skypjack

4

"hello" bir const char * olduğunu ve dolaylı olarak da bir std::string oluşturmak için kullanılan bool dönüştürülebilir, bir std::string değildir. Başka bir deyişle
, bu sadece çalışıyor:

int main() { 
    bool b = "foo"; 
    (void)b; 
} 

@aschepler yorumlarına belirtildiği gibi:

bool için const char* gelen örtük dönüştürme const char* gelen kullanıcı tanımlı dönüşüm göre tercih edilir

std::string. int bir seçenek değildir.

+0

Burada UB yok. Const char * '' bool'dan dolaylı dönüşümü, 'const char * '' dan' std :: string' 'e kadar kullanıcı tanımlı dönüştürme üzerinde tercih edilir. 'int' bir seçenek değildir. – aschepler

+0

@aschepler Sabit, teşekkürler. – skypjack