Home > Mobile >  How is it possible to unite multiple types in the operator function called by std::visit in C ?
How is it possible to unite multiple types in the operator function called by std::visit in C ?

Time:10-29

I am using std::variant and std::visit to call operator functions. I have a lot of variants (which mostly inherit from one superclass), but most of the operator functions should return the same value. Is there a way to have one operator function, which is called everytime one of those child-classes is called (such as if a normal function is called with a child-class as a parameter and if there is no such function, the (overlaoded) function is called, if the super-class is a parameter.

This may be easier to understand with an example:

I have two superclasses: struct function_node; struct nary_node; I also have multiple classes which inherit from those superclasses:

struct addition_node : function_node, nary_node;
struct division_node: function_node, nary_node;
struct cos_node: function_node, nary_node;

I have another class which has those classes as variants:

struct value_node{
   var get_variant(){
      return std::variant<
                 addition_node*,
                 division_node*,
                 cos_node*
              >;
   }
};

I finally have a last class (constant_checker), which evaluates the expressions.

double eval(value_node* node){
   return std::visit(*this, node->get_variant());
}

In this last class I am currently having multiple operator functions of the form:

double operator(division_node* node){
   return 0; 
}

This works fine, but I actually have multiple dozen of those children-nodes. Since the operator function should all return the same value, I want a single operator function for this, e.g.

double operator(function_node* node){
   return 0;
}

I have tried it in this exact way, but I receive the error

3>C:\...\include\variant(1644): error C2893: Failed to specialize function template 'unknown-type std::_C_invoke(_Callable &&,_Types &&...) noexcept(<expr>)'
3>C:\...\include\variant(1644): note: With the following template arguments:
3>C:\...\include\variant(1644): note: '_Callable=ale::util::constant_checker &'
3>C:\...\include\variant(1644): note: '_Types={ale::minus_node *}'
3>C:\...\include\variant(1656): error C2955: 'std::_All_same': use of class template requires template argument list

This error will go away, if I insert the operator function for this exact node (minus_node in this case) and then occurr again for the other nodes, so appearently the general oeprator function is not called.

Is there any solution to this or do I have to keep every operator function?

CodePudding user response:

Just use template operator():

template<class Node>
double operator()(Node* node) {
  if constexpr (std::is_same_v<Node, addition_node>) {
    // ...
  } else if constexpr (std::is_same_v<Node, division_node>) {
    // ...
  }
}

CodePudding user response:

Your visitor should be in a way that all:

  • visitor(variant1);
  • visitor(variant2);
  • ..
  • visitor(variantN);

are valid.

So yes you can group some.

Here

double operator(function_node* node){ return 0; }

would suffice.

Demo.

  • Related