Reducer iterator for functions that may or may not return a value

The following function applies a functor to each element and reduces the return value:

template <class FCT, class RED> RED::TYPE forAllElements(FCT functor, RED reducer){ for(/* all elem in elements */){ reducer(functor(elem)); } return reducer.value; } 

Now, sometimes I may need to just call the functor for all elements and not reduce anything. Basically, I would like to have something like:

 class FunctorThatReturnsNothing{ void operator() (Elem e){ // do something, return nothing... } } class DummyReducer{ using TYPE = void; // ??? something like that ??? template <class FCT> void operator() (/* ??? what here */){ // do nothing... } } forAllElements(FunctorThatReturnsNothing(), DummyReducer()); 

But this will not compile, since I have reducer(functor(elem)) , where the nonexistent return value of the void function is taken as an argument.

Is there a way to make it work for void functors without duplicating forAllElements for the case of void and not void ?

(For people suspecting an XY problem: I basically know different approaches to iterating and pruning, and I think the presented callback approach is suitable for my case. I'm just wondering how I can avoid code duplication to β€œreturn” the value + the abbreviation "and the case is" just a callback ".)

+5
source share
3 answers

I think you can just create a VoidReducer class, but instead of return reducer.value; you will need return reducer.getvalue(); . Then you just do void VoidReducer::getvalue(){} .

I have not tested this, but the idea should work. You are allowed to return f(); if both f and the current function are of return type void .

EDIT
Now that I have carefully read the question, I see that the problem you are asking is the reducer(functor(elem)); line reducer(functor(elem)); .
To do this, I sent time to compile based on decltype(functor(elem)) .

 template <class Functor, class Reducer, class Elem> void Combine(Functor functor, Reducer & reducer, Elem elem, std::true_type) { functor(elem); } template <class Functor, class Reducer, class Elem> void Combine(Functor functor, Reducer & reducer, Elem elem, std::false_type) { reducer(functor(elem)); } template <class Functor, class Reducer, class Elem> void Combine(Functor functor, Reducer & reducer, Elem elem) { Combine(functor, reducer, elem, std::is_same<decltype(functor(elem)), void>()); } 

Then calling Combine instead of reducer(functor(elem)) will correctly reduce the return value of functor if and only if it is not empty.

PS: Sprinkle links and std::forward calls to taste.

+1
source

If you still want to use your forAllElements function, if you use std::for_each you can create an overload of a function that does not accept the reducer, and just use std::for_each internally:

 template <class FCT> void forAllElements(FCT functor){ std::for_each(std::begin(...), std::end(...), functor); } ... forAllElements(FunctorThatReturnsNothing()); 

If it is not possible to get "iterators" for your container (if you use a non-standard container or pointers), you can, of course, have your own loop and just call functor .

+1
source

A clean and flexible approach is to return the function object itself, and not the hard code value .

 template <class FCT, class RED> RED forAllElements(FCT functor, RED reducer){ for(/* all elem in elements */){ reducer(functor(elem)); } return reducer; } 

As a result, an operation may not have a return value or even more than one return value with informative names.

Your original method can be considered as a convenient wrapper over this primitive component:

 template <class FCT, class RED> RED::TYPE forAllElements_convenience(FCT functor, RED reducer){ return forAllElements(functor, reducer).value; } 
0
source

All Articles