Reputation: 35980
I have the following code:
typedef boost::variant<LandSearchParameter, WaterSearchParameter> SearchParameter;
enum Visibility{
CLEAR,
CLOUDY,
FOG,
SMOKE
};
class DetectionGenerator : public boost::static_visitor<double>{
public:
DetectionGenerator(const EnvironmentalFactors& factors);
double operator()(const LandSearchParameter& land, Visibility vis) const;
double operator()(const WaterSearchParameter& water, Visibility vis) const;
private:
const EnvironmentalFactors mFactors;
};
but if I try to use it with boost::apply_visitor
in the following manner:
SearchParameter param = globeCover.generateSearch(lat, lon, altitude);
Visibility vis = weather.generateVisibility(lat, lon, altitude, bearing);
DetectionGenerator detectGen(envFactors);
double prob = boost::apply_visitor(detectGen, param, vis);
and get the following from gcc:
error: no matching function for call to
‘apply_visitor(const SearchRescue::DetectionGenerator&, const boost::variant<boost::tuples::tuple<double, double, double, double, double, bool, bool, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>, boost::tuples::tuple<std::size_t, std::size_t, double, double, double, bool, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>&, SearchRescue::Visibility)
If I attempt to wrap the Visibility
enum within a boost::variant
I get the same error only instead of Visibility
it reads all that junk above and whatever name I chose for the variant. I've read over the docs on boost for binary visitation but I'm at a loss. Due note, all these things are within the same namespace.
Update:
It was my attempt that was the problem. Not shown above was that I had the visitor as a const
variable. Once I took the const
out of the picture, it compiled. Thank you all for trying to help me out. Wish I could give more upvotes.
Upvotes: 8
Views: 12948
Reputation: 62975
@Boaz Yaniv's answer is 100% correct. The boost::apply_visitor<>
docs state directly:
Overloads accepting two operands invoke the binary function call operator of the given visitor on the content of the given variant operands.
Yaniv's suggested approach for remedying that – taking a Visibility
object in the visitor's constructor – is also the proper fix. You indicated that such an approach did not work for you; I'll warrant that the problem was in your attempt and not in the approach. ;-] Here's code that compiles:
#include <boost/variant.hpp>
struct LandSearchParameter { };
struct WaterSearchParameter { };
struct EnvironmentalFactors { };
typedef boost::variant<
LandSearchParameter,
WaterSearchParameter
> SearchParameter;
enum Visibility
{
CLEAR,
CLOUDY,
FOG,
SMOKE
};
struct DetectionGenerator : boost::static_visitor<double>
{
DetectionGenerator(EnvironmentalFactors const& factors, Visibility vis)
: mFactors(factors),
mVis(vis)
{ }
double operator ()(LandSearchParameter const&) const { return 0.; }
double operator ()(WaterSearchParameter const&) const { return 0.; }
private:
EnvironmentalFactors mFactors;
Visibility mVis;
};
int main()
{
SearchParameter param = LandSearchParameter();
EnvironmentalFactors const envFactors;
DetectionGenerator const detectGen(envFactors, CLOUDY);
double const prob = boost::apply_visitor(detectGen, param);
}
If this approach continues to fail to work for you then you'll need to edit your question and update it with your actual, current code.
P.S. Your approach of making Visibility
a single-type boost::variant<>
should work also, though it seems silly to me. For reference, this compiles:
#include <boost/variant.hpp>
struct LandSearchParameter { };
struct WaterSearchParameter { };
struct EnvironmentalFactors { };
typedef boost::variant<
LandSearchParameter,
WaterSearchParameter
> SearchParameter;
enum VisibilityT
{
CLEAR,
CLOUDY,
FOG,
SMOKE
};
typedef boost::variant<VisibilityT> Visibility;
struct DetectionGenerator : boost::static_visitor<double>
{
explicit DetectionGenerator(EnvironmentalFactors const& factors)
: mFactors(factors)
{ }
double operator ()(LandSearchParameter const&, VisibilityT const) const
{ return 0.; }
double operator ()(WaterSearchParameter const&, VisibilityT const) const
{ return 0.; }
private:
EnvironmentalFactors mFactors;
};
int main()
{
SearchParameter param = LandSearchParameter();
EnvironmentalFactors const envFactors;
DetectionGenerator const detectGen(envFactors);
Visibility vis = CLOUDY;
double const prob = boost::apply_visitor(detectGen, param, vis);
}
Upvotes: 9
Reputation: 6424
boost::apply_visitor only takes a visitor that takes a single argument, so it won't accept your visitor. You may be able to fix it with some binding, but I think a nicer solution would be just to add the Visibility argument at your DetectionGenerator class constructor:
class DetectionGenerator : public boost::static_visitor<double>{
public:
DetectionGenerator(const EnvironmentalFactors& factors, Visibility vis);
double operator()(const LandSearchParameter& land) const;
double operator()(const WaterSearchParameter& water) const;
private:
const EnvironmentalFactors mFactors;
const Visibility mVis;
};
SearchParameter param = globeCover.generateSearch(lat, lon, altitude);
Visibility vis = weather.generateVisibility(lat, lon, altitude, bearing);
DetectionGenerator detectGen(envFactors, vis);
double prob = boost::apply_visitor(detectGen, param);
And as for binary visitation, I don't think this is what you're looking for. It allows apply_visitor to take two arguments, but both arguments must be variants.
Upvotes: 8