boost :: variable — почему это «const char *» преобразован в «bool»?

Я объявил boost::variant который принимает три типа: string, bool а также int, Следующий код показывает, что мой вариант принимает const char* и преобразует его в bool, Это нормальное поведение для boost::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
тип: строка -> некоторая строка

Если я удаляю тип bool из MyVariant и меняю его на это:

typedef variant<string, int> MyVariant;

const char* больше не преобразуется в bool, На этот раз он конвертируется в string и это новый вывод:

тип: строка -> некоторая строка
тип: строка -> некоторая строка

Это указывает на то, что variant пытается сначала преобразовать другие типы в bool а затем string, Если преобразование типов является чем-то неизбежным и всегда должно происходить, есть ли способ дать преобразование string более высокий приоритет?

14

Решение

Я не думаю, что это как-то связано с 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 [править: как говорит Джеймс, вы можете написать другой класс, который использует 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 конструктор.

10

Другие решения

Это не имеет ничего общего с boost::variant, но в том порядке, в котором C ++ выбирает применяемые преобразования. Прежде чем пытаться использовать пользовательские преобразования (помните, что std::string является определяемым пользователем классом для этой цели), компилятор попробует встроенные преобразования. Там нет встроенного преобразования из const char* в int, но согласно §4.12 в стандарте:

Значение типа указателя […] типа […] можно преобразовать в значение типа bool.

Так что компилятор с радостью преобразует ваши const char* к bool и никогда не рассматривает возможность преобразования его в std::string,

10