I'm using boost::variant
quite often in my projects. My colleagues now came up with the idea to pass around instances of specific boost::static_visitor<int>
in order to customize the type of visitation. She had some code like the following:
#include <boost/variant.hpp>
#include <iostream>
typedef boost::variant<int, std::string> TVar;
struct Visitor1 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) {
return 42;
}
};
struct Visitor2 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) {
return 21;
}
};
int adder(const boost::static_visitor<int>& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
int main(int argc, char **args) {
Visitor1 v1;
Visitor2 v2;
TVar x;
std::cout << adder(v1, x) << std::endl;
std::cout << adder(v2, x) << std::endl;
}
It looks perfectly sound to me, but it doesn't compile. My compiler says that expression will not yield a function that takes one 1 argument
somewhere insider .
What are we doing wrong?
There's an overload for apply_visitor
that takes only the visitor. This returns a partially applied function object that suits your needs, I guess:
This overload returns a
Personally, I like to add an overload to the visitor object like this:
struct MyVisitor {
typedef void result_type;
template <typename... Ts>
result_type operator()(boost::variant<Ts...> const& v) const {
return boost::apply_visitor(*this, v);
}
// optionally repeat for non-const `v`
// normal variant handling overloads
};
That way, you can simply use the visitor object as the function oject.
Firstly, you should mark your visitors' operator()
overloads as const
:
struct Visitor1 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) const {
return 42;
}
};
struct Visitor2 : public boost::static_visitor<int> {
template<typename T>
result_type operator()(const T&) const {
return 21;
}
};
Then, you need to change your adder to accept a template parameter instead of boost::static_visitor
- it is your Visitor1
type that contains the operator()
overload with the logic you desire. You need the "correct type" for the visitation to take place.
template <typename T>
int adder(const T& visitor, const TVar& visitable) {
return visitable.apply_visitor(visitor) + 1;
}
live wandbox example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With