19

、、およびboost::variantの3つのタイプを受け入れるを宣言しました。次のコードは、私のバリアントがそれを受け入れてに変換することを示しています。リストにないタイプを受け入れて変換するのは正常な動作ですか?stringboolintconst char*boolboost::variant

#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ます。型変換が避けられないものであり、常に発生する必要がある場合、変換をstringより高い優先度にする方法はありますか?

4

3 に答える 3

13

これは、とは関係ありませんがboost::variant、C++が適用する変換を選択する順序とは関係ありません。std::stringユーザー定義の変換を使用する前に(この目的ではユーザー定義のクラスであることを忘れないでください)、コンパイラーは組み込みの変換を試行します。const char*からへの組み込みの変換はありませんがint、標準の§4.12によると:

[...]ポインタ[...]型のprvalueは、bool型のprvalueに変換できます。

したがって、コンパイラはあなたconst char*をに喜んで変換しbool、それをに変換することを検討することは決してありませんstd::string

更新:この明らかに不要な変換が修正されているようです。修正の技術的な説明はここにあります。

于 2012-11-07T11:30:59.980 に答える
12

これは特に関係があるとは思いません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のコンストラクターを変更する方法がわかりません[編集:Jamesが言うように、実装で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/intMyVariant(true)int

于 2012-11-07T11:23:02.877 に答える
0

使用したいのは文字列リテラル(const char *自体ではない)だと思います。

次に、std :: string_literals(std :: stringのsサフィックス)を試すことができます。

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

#include <string>
using namespace std::string_literals; // enables s-suffix for std::string literals

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"s; // use s-suffix ("some string"s is std::string, not const char *
    apply_visitor(TestVariant(), s1);

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

    return 0;
}

出力:

type: string -> some string
type: string -> some string
于 2021-07-22T19:06:46.833 に答える