Search code examples
c++boostvariantboost-variantmlpack

Error while trying to use the boost::variant - "No matching function for call"


I'm continuously getting errors saying "No matching call for function" while using boost::variant. Below is my code snippet.

struct Output {
    int a;
    float b;
}
    
typedef boost::variant<ClassA<X, Y>, ClassA<>> ClassAGeneric;

class Operation: public boost::static_visitor<Output>
{
public:
    double d;
    int a;
    float b;
    
    Output operator()(ClassA<X, Y> obj) const
    {
        obj.operate(d, a, b);
        return (Output) {a, b};
    }
    
    Output operator()(ClassA<> obj) const
    {
        obj.operate(d, a, b);
        return (Output) {a, b};
    }
};

I'm getting this error in the obj.operate() call in the first operator() that is defined.

I tried the passing the templates as well like mentioned in the other answer, but I still see an error.

obj.operate<X,Y>(d,a,b);

Could somebody help me with this?

I could give the exact scenario as well here :

struct Output{
  Row<size_t> predictions;
  mat probabilities;
};
typedef boost::variant<RandomForest<GiniGain, RandomDimensionSelect>, RandomForest<>> RandomForestGeneric;

class Operation: public boost::static_visitor<Output>
{
public:
    mat dataset;
    Row<size_t> predictions;
    mat probabilities;
    
    Output operator()(RandomForest<GiniGain, RandomDimensionSelect> obj) const
    {
        obj.Classify(dataset, predictions, probabilities);
        return (Output) {predictions, probabilities};
    }
    
    Output operator()(RandomForest<> obj) const
    {
        obj.Classify(dataset, predictions, probabilities);
        return (Output) {predictions, probabilities};
    }
};

Solution

  • Here's my imagined self-contained tester:

    Live On Coliru

    #include <boost/variant.hpp>
    #include <iostream>
    
    struct X;
    struct Y;
    template <typename... T> struct ClassA {
        void operate(double d, int a, float b) const
        {
            std::cout << __PRETTY_FUNCTION__ << "(" << d << "," << a << "," << b << ")\n";
        }
    };
    
    struct Output {
        int   a;
        float b;
    };
    
    typedef boost::variant<ClassA<X, Y>, ClassA<>> ClassAGeneric;
    
    class Operation // : public boost::static_visitor<Output>
    {
      public:
        double d;
        int    a;
        float  b;
    
        Output operator()(ClassA<X, Y> const& obj) const
        {
            obj.operate(d, a, b);
            return Output{a, b};
        }
    
        Output operator()(ClassA<> const& obj) const
        {
            obj.operate(d, a, b);
            return Output{a, b};
        }
    };
    
    int main() {
        Operation op {3.14, 42, 9e-2f};
    
    
        ClassAGeneric v1 = ClassA<X,Y>{};
        ClassAGeneric v2 = ClassA<>{};
        apply_visitor(op, v1);
        apply_visitor(op, v2);
    }
    

    Prints

    void ClassA::operate(double, int, float) const with T = {X, Y}
    void ClassA::operate(double, int, float) const with T = {}

    Unsurprisingly that works. Now, one pitfall could be when you failed to make the operate member function const and the arguments are, in fact, const.

    Also note that you can greatly simplify the visitor (especially assuming C++14): Live On Coliru