Я объявил 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
более высокий приоритет?
Я не думаю, что это как-то связано с 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
конструктор.
Это не имеет ничего общего с boost::variant
, но в том порядке, в котором C ++ выбирает применяемые преобразования. Прежде чем пытаться использовать пользовательские преобразования (помните, что std::string
является определяемым пользователем классом для этой цели), компилятор попробует встроенные преобразования. Там нет встроенного преобразования из const char*
в int
, но согласно §4.12 в стандарте:
Значение типа указателя […] типа […] можно преобразовать в значение типа bool.
Так что компилятор с радостью преобразует ваши const char*
к bool
и никогда не рассматривает возможность преобразования его в std::string
,