1

I have spent the past hours trying to find an elegant solution but however i am unable to.

Description: I would like to have a default implementation for a visitor functor in class visitor_base_all and then each of the derived classes for example visitor_override would define the method just for what it needs. I understand that this does not work because the operator() is not passed to the derived classes (due to C++ not overload across scopes which is fair enough), so the question is how to do this exactly? I was thinking of doing it with overloaded lambdas or having a switch in the virtual base_class method and then each derived class overloading only the virtual methods called in that switch.

Regarding the lambdas, I am not sure on how to do it. I have read the following before: pablo_arias arne-mertz and stack_overflow_question but i am still a bit confused on what would be the proper correct way forward.

Thank you for your time

Short question: Proper c++17 way of making below compile/work. What is the proper way to generalize it for a big number of derived types in the variant and derived classes?

(Post comments-edit) My problem is more generalized for a big number of classes and a lot more types, so if possible i would prefer to template/generalize it somehow. Below is the example with just 1 derived class, but what would be a proper way with having 10 classes? (I wouldn't want to declare using in each of them if it can be avoided).

#include <variant>

struct A{};
struct B{};
struct C{};
using type_x = std::variant<A,B,C>;

class base_class
{
protected:
    struct visitor_base_all
    {
        void operator()(const A& a){std::cout<<"A_base" << std::endl;}
        void operator()(const B& b){std::cout<<"B_base" << std::endl;}
        void operator()(const C& c){std::cout<<"C_base" << std::endl;}
    };
    virtual void run(type_x evt){return std::visit(visitor_base_all{}, evt);}
};

class derived_class :public base_class
{
    struct visitor_override : public visitor_base_all
    {
        void operator()(const C& c){};
    };
     virtual void run(type_x evt){return std::visit(visitor_override{}, evt);}
};
eucristian
  • 391
  • 3
  • 17
  • Can you provide a [mre] on which solutions might be based? – bracco23 Oct 29 '19 at 15:41
  • I think you want to explore the using declaration. `using visitor_base_all::operator();` inside visitor_override should do the trick. – n. m. could be an AI Oct 29 '19 at 15:43
  • 1
    @Barry: Even if `using` is the solution in both cases, OP's issue is not an issue with multiple base classes, but hiding member methods... Not the more appropriated duplicates IMO. – Jarod42 Oct 29 '19 at 15:51
  • 1
    Hmm. @Barry it’s not immediately obvious to me how this is a duplicate (this question is about visitors, the other one about multiple inheritance … there isn’t much overlap at first sight), or how the linked answers answer this question. – Konrad Rudolph Oct 29 '19 at 15:51
  • @Jarod42 you can [edit](https://stackoverflow.com/questions/originals/58610727/edit) the duplicate resolution, add another duplicate question, and/or remove an inappropriate one. – n. m. could be an AI Oct 29 '19 at 15:53
  • @KonradRudolph It's exactly a duplicate. The reason OP's code doesn't work is because we're not merging across two different scopes, and you need a `using` declaration to bring in the other names. The fact that this case is specifically about visitors is not relevant. – Barry Oct 29 '19 at 15:54
  • 1
    @KonradRudolph the dupe *question* is not too similar, but its *answer* is a perfectly good one for this Q too. You can add other dupes if you find a more appropriate one (there's a lot of those). – n. m. could be an AI Oct 29 '19 at 15:56
  • In this case, it's once we find a name in the derived we don't continue looking in the base... instead of if we find a name in different bases, we don't consider it. But it's the same fundamental principle (which is even cited in OP) with the same solution. – Barry Oct 29 '19 at 15:57
  • Perhaps a better solution would be to make the `void operator()` virtual, and just override what you need. This is how the visitor pattern normally works. If you find yourself not needing it to be virtual, you are probably misusing the pattern. – n. m. could be an AI Oct 29 '19 at 16:06
  • I apologise, my question is not clear enough. I know how to solve the compilation problem, but my problem is that i have a lot of derived classes and a lot of cases and i wouldn't want to use using base::operator() in each of them as this would be very ugly.(even if i would have a macro for it, still ugly imo) Again, my bad and your comments are valid. would it be ok if i edit the question a bit? Based on the edits i would say that it is no longer a duplicate? – eucristian Oct 29 '19 at 16:15
  • @eucristian: Do you have chaining of derived classes? one which implement `operator()` for `A` another for `B` and a last one for `C`, or is it just default or provided? – Jarod42 Oct 29 '19 at 16:32
  • @Jarod42 yes, exactly. but i saw in one of Barry's duplicate the collector template. now sure how to implement it exactly though. trying now – eucristian Oct 29 '19 at 16:35
  • 1
    Are you looking for something like [that](http://coliru.stacked-crooked.com/a/28aac2c9b161883c) – Jarod42 Oct 29 '19 at 16:35
  • yes. this is it.thank you very much mister Jarod@Jarod42 – eucristian Oct 29 '19 at 16:35
  • @Jarod42 would it be possible to do your example with variadic templates? – eucristian Oct 29 '19 at 17:36
  • @eucristian: I would say yes with recursion. – Jarod42 Oct 29 '19 at 17:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/201565/discussion-between-eucristian-and-jarod42). – eucristian Oct 29 '19 at 18:39

0 Answers0