Я наблюдаю поведение в следующем коде, которое я не понимаю. Дело в том, что если я объявлю вторую перегрузку operator()
как один из следующих:
bool operator()(T other) const
bool operator()(const T &other) const
Выход программы:
строка
Но если я использую следующую декларацию:
bool operator()(T &other) const
Выход будет:
другой тип
Может кто-нибудь объяснить, почему operator()(const string &other)
не вызывается в последнем случае?
#include "boost/variant/variant.hpp"#include "boost/variant/apply_visitor.hpp"
using namespace std;
using namespace boost;
typedef variant<string, int> MyVariant;class StartsWith
: public boost::static_visitor<bool>
{
public:
string mPrefix;
bool operator()(const string &other) const
{
cout << "string" << endl;
return other.compare(0, mPrefix.length(), mPrefix) == 0;
}
template<typename T>
bool operator()(T &other) const
{
cout << "other type" << endl;
return false;
}
StartsWith(string const& prefix):mPrefix(prefix){}
};
int main(int argc, char **argv)
{
MyVariant v(string("123456"));
apply_visitor(StartsWith("123"), v);
return 0;
}
У тебя есть const
проблема здесь.
Вы передаете не постоянный объект apply_visitor
— поэтому неконстантные члены объекта передаются посетителю. Так что в вашем случае это string&
— ссылка на тип строки. Этот шаблон точно соответствует ему:
template<typename T>
bool operator()(T &other) const
Так и выбрано. Эта функция не является точным соответствием — она пропущена:
bool operator()(const string &other) const
Конечно, если вы предоставите этого оператора:
bool operator()(string &other) const
тогда он будет выбран, так как не шаблонная функция рассматривается перед первым шаблоном.
Решение таково: либо предоставьте посетителю метод, который принимает строковую ссылку (не const), либо передайте константный вариант для применения …
Первое решение — удалить const из строкового оператора:
bool operator()(/*const*/ string &other) const
// ^^^^^^^^^ remove it
Второе решение — передать объект const:
const MyVariant& cv = v;
apply_visitor(StartsWith("123"), cv);
// ^^ const object passed here
Третье решение — добавить спецификатор const для общего посетителя:
template<typename T>
bool operator()(const T &other) const
// ^^^^^
Решения 1-го и 3-го лучше, чем 2-го — вы должны передать согласованный посетитель для вашего варианта, const имеет сильное значение, когда компилятор должен выбрать соответствующую функцию.
Других решений пока нет …