2017-05-20 4 views
11

My std::variantは空(std::monostate)、intstd::stringまたはboolを含むことができます。私のバリアントはstd :: stringをboolに変換するのはなぜですか?

var = "this is my string"という文字列を入力すると、文字列ではなくboolに変換されます。型を明示的に宣言すると、var = std::string("this is my string")が機能します。それはなぜですか、私はそれを避けるために何かできますか?

#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  
} 

EDIT 私のコードのユーザーが明示的にstring秒をしないかもしれないので、私はそれをキャッチしたいです。それ以外の場合は、エラーの原因になります。 char*が渡されたかどうかを確認するテンプレートヘルパー関数を作成し、そうであればstd :: stringを作成します。うまくいく。これを簡単にするためのヘルプは高く評価されています!

EDIT 2 デフォルトパラメータ/タイプとしてstd::monostateを宣言することでmake_varは、引数なしで呼び出されたときに、それも動作します。

#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

'のstd ::に好まれるSTRING'べき理由聞いてもう一つの問題は、あります'ブール'?どちらも配列の減衰と型変換が必要です。 – juanchopanza

+1

テンプレートを使用した特に私の回避策;-)を使用して、私の素敵な答えをhttp://stackoverflow.com/questions/44021989/implicit-cast-from-const-string-to-boolで見ることができます。しかし、ユーザー定義のリテラル(以下)のAngewの使用はより控えめです。 – Bathsheba

+0

短い答え:それはあなたが与えた 'std :: string'ではないので、そうではありません。 –

答えて

27

"hello"のタイプはconst char [6]であり、これはconst char *に減衰します。 const char *からboolへの変換はビルトイン変換であり、const char *からstd::stringへの変換は前者の変換であることを意味します。

あなたが++> = 14 Cを使っているので、あなたは文字通りstd::stringを示すためにリテラル接尾sを使用することができますが:

using namespace std::string_literals; 

var contains_string = "hello"s; 
+1

なぜ、 'bool'の代わりに' int'型を拾わなかったのですか? – skypjack

+15

@skypjack C++での 'int'変換への暗黙のポインタがないためです。 – Angew

+0

それは確かに意味があります。ありがとうございました。:-) – skypjack

4

"hello"それはconst char *だと、暗黙的にstd::stringを構築するために使用されるだけでなく、ブール値に変換することができ、std::stringではありません。他の点で
が、これはうまく動作します:

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

@ascheplerのコメントで述べたように:

const char*からboolへの暗黙の変換がconst char*からユーザ定義の変換よりも好ましいですstd::stringintはオプションではありません。

+0

ここにUBはありません。 'const char *'から 'bool'への暗黙の変換は、' const char * 'から' std :: string'へのユーザ定義変換よりも優先されます。 'int'はオプションではありません。 – aschepler

+0

@ascheplerありがとう、ありがとう。 – skypjack

関連する問題