2012-11-07 15 views
14

私はstring,boolおよびintの3種類を受け入れるboost::variantと宣言しました。次のコードは、私のバリアントがconst char*を受け入れ、boolに変換していることを示しています。 boost::variantがリストにない型を受け入れて変換するのは正常な動作ですか?boost :: variant - "const char *"が "bool"に変換されるのはなぜですか?

#include <iostream> 
#include "boost/variant/variant.hpp" 
#include "boost/variant/apply_visitor.hpp" 

using namespace std; 
using namespace boost; 

typedef variant<string, bool, int> MyVariant; 

class TestVariant 
    : public boost::static_visitor<> 
{ 
public: 
    void operator()(string &v) const 
    { 
     cout << "type: string -> " << v << endl; 
    } 
    template<typename U> 
    void operator()(U &v)const 
    { 
     cout << "type: other -> " << v << endl; 
    } 
}; 

int main(int argc, char **argv) 
{ 
    MyVariant s1 = "some string"; 
    apply_visitor(TestVariant(), s1); 

    MyVariant s2 = string("some string"); 
    apply_visitor(TestVariant(), s2); 

    return 0; 
} 

出力:

タイプ:その他 - > 1
種類:文字列 - >いくつかの文字列

私はMyVariantからbool型を削除して、このように変更した場合:

typedef variant<string, int> MyVariant; 

const char*もはやboolに変換されません。今回はそれがstringに変換されます、これは新しい出力されます。

種類:文字列 - >いくつかの文字列
種類:文字列 - >これはvariant試みは、他の種類を変換することを示しているいくつかの文字列

最初はbool、次にになります。型変換が不可避であり、常に起こるはずですが、より高い優先度の変換をstringに与える方法はありますか?

答えて

10

これは特に、boost::variantとは関係がありません。これは、どのコンストラクタが過負荷解決によって選択されるかについてです。同じことは、オーバーロードされた関数で発生します:

#include <iostream> 
#include <string> 

void foo(bool) { 
    std::cout << "bool\n"; 
} 

void foo(std::string) { 
    std::cout << "string\n"; 
} 

int main() { 
    foo("hi"); 
} 

出力:

bool 

私はバリアントをコンストラクタものを変更する方法を知りませんが、[編集]を持っている:ジェームズが言うように、あなたが書くことができます実装でVariantを使用する別のクラスです。次に、正しいことを行うconst char*コンストラクタを提供することができます。]

多分、バリアントのタイプを変更することができます。別のオーバーロードの例:

struct MyBool { 
    bool val; 
    explicit MyBool(bool val) : val(val) {} 
}; 

void bar(MyBool) { 
    std::cout << "bool\n"; 
} 

void bar(const std::string &) { 
    std::cout << "string\n"; 
} 

int main() { 
    bar("hi"); 
} 

出力:

string 

は、残念ながら今はbar(MyBool(true))代わりのfoo(true)記述する必要があります。 string/bool/intのバリアントの場合はさらにstring/MyBool/intのバリアントに変更すると、MyVariant(true)intコンストラクタを呼び出します。

+6

説明を完了するには:ポインタ型から 'bool'への暗黙的な変換があり、組み込みの暗黙の変換は常にユーザー定義の変換より優先して選択されます。 ( 'char *'から 'std :: string'への変換はユーザ定義としてカウントされます。)コンストラクタの変更に関しては、クラスを別のクラスにラップするか、そこから派生させることができます。文脈によっては、これらの1つが適切かもしれません。どちらにもいくつかの欠点があります。 –

+0

私は1つの解決策は、 'MyVariant'から' bool'を削除し、代わりに0と1の値を使うことだと思います。 – Meysam

+0

@マイザム:はい。私はそれを推薦することを考えましたが、おそらく、 'MyVariant'を' false'で初期化した 'MyVariant'と違うように' 0'で初期化したかったと思いました。それらが同じであればOKですが、 'bool'を削除してください。彼らの意味が異なる場合、それほど単純ではありません。 –

9

これは、boost::variantとは関係ありませんが、適用するコンバージョンをC++が選択する順序です。ユーザー定義の変換を使用する前に(この目的のためにstd::stringがユーザー定義のクラスであることを覚えておいてください)、コンパイラは組み込みの変換を試行します。そこconst char*からintへの組み込みの変換はありませんが、規格に§4.12に従う:

[...]のポインタ[...]タイプはタイプのprvalueに変換することができるのprvalueブール

ので、コンパイラは喜んでboolにごconst char*を変換し、決してstd::stringに変換検討して取得します。

+0

これは、今日は、オーバーロードされたメソッドのペアで、私はちょうど 'bool'を取ったメソッド、もう一つは' const std :: string& 'メソッドを使いました。残念です! – davidbak

関連する問題