1

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};
    }
};
Ambi
  • 423
  • 3
  • 7
  • 17
  • 2
    Please provide [mcve], you can start with this: https://godbolt.org/z/EcGPfberK or this: https://godbolt.org/z/Pfvs3vfvo – Marek R Nov 16 '21 at 16:26

1 Answers1

1

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

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thank you for your response but trying this didn't work for me in my use case. I'm trying to use RandomForest of mlpack with and without hyperparameters. So the typedef is like below - typedef boost::variant, RandomForest<>> RandomForestGeneric; And the operate is member function of RandomForest class defined in mlpack - Classify() – Ambi Nov 17 '21 at 03:52
  • This is why you need self-contained code in the question. I suggest you look at the suggestion about const members I made. – sehe Nov 17 '21 at 04:00
  • Considering the fact that `RandomForest` sounds like it may not be copyable, or expensive to copy, consider passing them by reference ([updated my answer code](https://stackoverflow.com/posts/69994428/revisions) to reflect that change). – sehe Nov 17 '21 at 04:01
  • I tried the same I still get the same error. error: no matching function for call to ‘mlpack::tree::RandomForest::Classify(const mat&, const arma::Row&, const mat&) const’ From the documentation I see that only one of the arguments(first one) is const. I'm not sure why all the parameters are getting converted to const. https://mlpack.org/doc/mlpack-git/doxygen/classmlpack_1_1tree_1_1RandomForest.html#a255d0a8b26a14cfd6a1f745568b83017 – Ambi Nov 17 '21 at 05:33
  • Why do you assume that "all the parameters are getting converted to const"? That seems a bold assumption. Again, without the code or even the complete error messages, you're just blindly (mis)interpreting the situation and hoping that we magically know what you're doing wrong. Good luck. – sehe Nov 17 '21 at 12:52
  • Thank you for the additional comments. I got the issue fixed. Keeping the parameters that are passed as global instead of local to the class has fixed the issue. The const keyword in the operator overload is trying to ensure that none of the member variables would change and the RandomForest cmember function is trying to do exactly that. Thanks a lot for your guidance and I was able to fix the issue. – Ambi Nov 17 '21 at 13:40
  • Ow. Don't use globals! Instead of making them global, consider marking them `mutable`. Better yet, just do not make the `operator()` const! See it live: http://coliru.stacked-crooked.com/a/e31fcd4a27553abc – sehe Nov 17 '21 at 13:47
  • And the lambda version of that: http://coliru.stacked-crooked.com/a/ab54817bd2731e8f (note the `mutable` and the output still verifies that the parameters are being updated) – sehe Nov 17 '21 at 13:50
  • Oh okay.. Thanks a lot for your inputs, I'm able to solve the problem. :-) – Ambi Nov 18 '21 at 07:23