Reputation: 3968
For some reason, using boost's variant(I know there is a c++17 version, I'm providing backwards compatibility here, and plus c++17 isn't fully supported by clang++ yet) leads to some strange behavior when using the visitor paradigm:
#include <iostream>
#include <boost/variant.hpp>
using boost::variant;
typedef boost::variant<double, std::string> term_t;
class plus_visitor : public boost::static_visitor<term_t> {
public:
term_t operator()(double lhs, double rhs) const{
return {lhs + rhs};
}
term_t operator()(double lhs, std::string rhs) const{
return {lhs + std::stoi(rhs)};
}
term_t operator()(std::string lhs, int rhs) const{
return operator()(rhs, lhs);
}
term_t operator()(std::string lhs, std::string rhs) const{
return std::stoi(lhs) + std::stoi(rhs);
}
};
int main(){
// term_t lhs {3.0};
term_t rhs {"10"};
term_t lhs {"3"};
term_t res = boost::apply_visitor(plus_visitor(), lhs, rhs);
std::cout << res << std::endl;
return 0;
}
It outputs 13 as expected.
#include <iostream>
#include <boost/variant.hpp>
using boost::variant;
typedef boost::variant<double, std::string> term_t;
class plus_visitor : public boost::static_visitor<term_t> {
public:
term_t operator()(double lhs, double rhs, double x) const{
return {lhs + rhs + x};
}
term_t operator()(double lhs, std::string rhs, double x) const{
return {lhs + std::stoi(rhs) + x};
}
term_t operator()(std::string lhs, double rhs, double x) const{
return operator()(rhs, lhs, x);
}
term_t operator()(std::string lhs, std::string rhs, double x) const{
return std::stoi(lhs) + std::stoi(rhs) + x;
}
};
int main(){
term_t rhs {"10"};
term_t lhs {"3"};
term_t x {3.0};
term_t res = boost::apply_visitor(plus_visitor(), lhs, rhs, x);
std::cout << res << std::endl;
return 0;
}
What's the deal here? Does apply_visitor
only work for 2 arguments?
I looked to the documentation and found that:
http://www.boost.org/doc/libs/1_36_0/doc/html/boost/apply_visitor.html
apply_visitor
works only for binary arguments or unary arguments! This sucks! How can I work around this and supply a 3rd one without being completely ugly in the syntax? Is there another boost
library function that allows more inputs? Why does the boost library not use variadic templates to allow for arbitrary sized apply_visitor
functions?
Upvotes: 1
Views: 358
Reputation: 109169
You're looking at documentation for Boost 1.36, which was released in 2008. If you look at the documentation for the current release, it lists the following apply_visitor
overloads
template<typename MultiVisitor, typename Variant1, typename Variant2,
typename Variant3>
typename MultiVisitor::result_type OR decltype(auto)
apply_visitor(MultiVisitor & visitor, Variant1 & operand1,
Variant2 & operand2, Variant3 & operand3, ... other_operands);
template<typename MultiVisitor, typename Variant1, typename Variant2,
typename Variant3>
typename MultiVisitor::result_type OR decltype(auto)
apply_visitor(const MultiVisitor & visitor, Variant1 & operand1,
Variant2 & operand2, Variant3 & operand3, ... other_operands);
The documentation also states
Overloads accepting three or more operands invoke the function call operator of the given visitor on the content of the given variant operands. ... Those functions are actually defined in a header
boost/variant/multivisitors.hpp
... That header must be manually included if multi visitors are meant for use.
So make sure you're using a recent Boost release, include the relevant header, define the missing operator()
overloads for the 3 argument example and your code should compile.
Upvotes: 2