Boost :: variant - Why does the template parameter take precedence over the const string parameter

I am observing behavior in the following code, which I do not understand. The thing is, if I declare the second operator() overload as one of the following:

 bool operator()(T other) const bool operator()(const T &other) const 

Program Output:

line

But if I use the following declaration:

 bool operator()(T &other) const 

The output will be:

another type

Can someone explain why operator()(const string &other) not called in the latter case?

 #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; } 
+6
source share
1 answer

You have a const problem.

You are not passing a const object to apply_visitor - so object members will not be passed. Therefore, in your case, this is string& - a reference to the type of string. This template is suitable for him:

 template<typename T> bool operator()(T &other) const 

So he is selected. This function is not an exact match - it is skipped:

 bool operator()(const string &other) const 

Of course, if you provide this statement:

 bool operator()(string &other) const 

then it will be selected, since a function without a template is considered before the template.

So, the solution: either provide a method in your visitor that accepts a link to the string (not const) - or use the option const const ...

The first solution is to remove const from the string statement:

 bool operator()(/*const*/ string &other) const // ^^^^^^^^^ remove it 

The second solution is to pass the const object:

 const MyVariant& cv = v; apply_visitor(StartsWith("123"), cv); // ^^ const object passed here 

The third solution is to add a const specifier for the common visitor:

 template<typename T> bool operator()(const T &other) const // ^^^^^ 

The solutions of the 1st and 3rd are better than the 2nd - you must go through the consecutive visitor of your option, const is of great importance when the compiler must select the appropriate function.

+6
source

All Articles