Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a member function in for each loop?

Tags:

c++

foreach

class

I'm trying to use std::for_each() instead of a normal for loop as a practice, but I can't pass a member function to for_each().

Here is the code:

class Class
{
    public :
        void func (int a)
        {
            cout << a * 3 << " ";
        }
}ob1;

int main()
{
    int arr[5] = { 1, 5, 2, 4, 3 };
    cout << "Multiple of 3 of elements are : ";
    for_each(arr, arr + 5, ob1);
}

It works only if this member function is void operator() (int a). I don't know why any other member function cannot be passed into for_each()!

like image 851
zaydoosh Avatar asked Oct 15 '25 04:10

zaydoosh


2 Answers

You are not passing any class method to for_each(), you are passing an object, which only works when the object implements operator().

To let for_each() call your Class::func() method, you would need to either:

  • implement operator() in your class:

    class Class
    {
    public:
        void func (int a)
        {
            std::cout << a * 3 << " ";
        }
    
        void operator()(int a)
        {
            func(a);
        }
    }ob1;
    
    std::for_each(arr, arr + 5, ob1);
    
  • use a separate delegate that implements operator() to call into your class.

    • you can define a custom functor (pre-C++11):

      struct functor
      {
          Class &obj;
      
          functor(Class &c) : obj(c) {}
      
          void operator()(int a)
          {
              obj.func(a);
          }
      };
      
      std::for_each(arr, arr + 5, functor(ob1));
      
    • or use std::bind() (C++11 and later):

      #include <functional>
      
      auto func = std::bind(&Class::func, &obj1, std::placeholders::_1);
      std::for_each(arr, arr + 5, func);
      
    • or use a lambda (C++11 and later):

      auto func = [&](int a){ obj1.func(a); };
      std::for_each(arr, arr + 5, func);
      
like image 155
Remy Lebeau Avatar answered Oct 16 '25 20:10

Remy Lebeau


The for_each function has several overloads which can be seen here.

C++ - std::for_each - Algorithm library

Defined in header algorithm

template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f ); 
// (1) (until C++20)  

template< class InputIt, class UnaryFunction >
constexpr UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f ); 
// (1) (since C++20)  

template< class ExecutionPolicy, class ForwardIt, class UnaryFunction2 >
void for_each( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryFunction2 f ); 
// (2)  (since C++17)  
  • 1) Applies the given function object f to the result of dereferencing every iterator in the range [first, last), in order.
  • 2) Applies the given function object f to the result of dereferencing every iterator in the range [first, last) (not necessarily in order). The algorithm is executed according to policy. This overload does not participate in overload resolution unless std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> is true.

For both overloads, if the iterator type is mutable, f may modify the elements of the range through the dereferenced iterator. If f returns a result, the result is ignored.

Unlike the rest of the algorithms, for_each is not allowed to make copies of the elements in the sequence even if they are trivially copyable.


Parameters

first, last -

  • the range to apply the function to

policy -

  • the execution policy to use. See execution policy for details.

f -

  • function object, to be applied to the result of dereferencing every iterator in the range [first, last)
  • The signature of the function should be equivalent to the following:
  • void fun(const Type &a);
  • The signature does not need to have const &.
  • The type Type must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type.

Type requirements

  • InputIt must meet the requirements of LegacyInputIterator.
  • ForwardIt must meet the requirements of LegacyForwardIterator.
  • UnaryFunction must meet the requirements of MoveConstructible. Does not have to be CopyConstructible
  • UnaryFunction2 must meet the requirements of CopyConstructible.

This tells you all of the requirements that are needed for your predicate, function object or functor that is needed to satisfy the condition(s) needed for for_each's last parameter. If you wish to avoid having all of your class's or custom data structures defining the operator() then you could write a generic functor that will implement the operator() for your class(es), or you could use a lambda. You can refer to Remy Lebeau's answer for implementation details.

like image 33
Francis Cugler Avatar answered Oct 16 '25 22:10

Francis Cugler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!