Search code examples
c++lambda

How to Make a helper function which accepts a lambda in C++


Right now I have a function which makes some changes in an array of uchar (will act as a LUT) so I can decide which transformation will be implemented on that LUT.

for (size_t i = 0; i <= 255; ++i)
{
    lut_transform[0].at<uchar>(i) = 255-i; //Inverse function
}
for (size_t i = 0; i <= 255; ++i)
{
    lut_transform[1].at<uchar>(i) = pow((float)i * 255,(1/2.0)); //Square Root function
}
for (size_t i = 0; i <= 255; ++i)
{
    lut_transform[2].at<uchar>(i) = pow((float)i, 3.0) / (255*255); //Cubic function
}

So I want to improve this and create a helper function which receives as a parameter the array and the function algorithm to implement. So should look something like this.

void transform_function_helper (std::vector<uchar>& vec_tf, lambda_arg f(int)){
  for (int i = 0; i < vec_tf.size(); ++i) {
    vec_tf.at<uchar>(i) = f(i);
  }
}
void current_function_already_working(){
  /* code */
  //replacing the 3 for for the calls to the helper function
  //lut_transform is a vector of uchar vector
  transform_function_helper(lut_transform[0], [](const int x) -> uchar { 255 - x; } );
  transform_function_helper(lut_transform[1], [](const int x) -> uchar { pow((float)x * 255,(1/2.0)); } );
  transform_function_helper(lut_transform[2], [](const int x) -> uchar { pow((float)x, 3.0) / (255*255); } );
  /*code*/
}

I hope this is clear.


Solution

  • You have three choices:

    1. use a plain C-style function pointer (since you are not using any capturing lambdas), eg:
    void transform_function_helper (std::vector<uchar>& vec_tf, uchar (*f)(size_t)) {
      for (size_t i = 0; i < vec_tf.size(); ++i) {
        vec_tf[i] = f(i);
      }
    
      /* alternatively:
      size_t i = 0;
      for (auto &elem : vec_tf) {
        elem = f(i++);
      }
      */
    }
    
    1. Use std::function, eg:
    #include <functional>
    
    void transform_function_helper (std::vector<uchar>& vec_tf, std::function<uchar(size_t)> f) {
      for (size_t i = 0; i < vec_tf.size(); ++i) {
        vec_tf[i] = f(i);
      }
    
      /* alternatively:
      size_t i = 0;
      for (auto &elem : vec_tf) {
        elem = f(i++);
      }
      */
    }
    
    1. Use a template function, eg:
    template<typename Callable>
    void transform_function_helper (std::vector<uchar>& vec_tf, Callable f) {
      for (size_t i = 0; i < vec_tf.size(); ++i) {
        vec_tf[i] = f(i);
      }
    
      /* alternatively:
      size_t i = 0;
      for (auto &elem : vec_tf) {
        elem = f(i++);
      }
      */
    }
    

    Either way, you can then call the helper function like this:

    void current_function_already_working(){
      /* code */
      //replacing the 3 for for the calls to the helper function
      //lut_transform is a vector of uchar vector
      transform_function_helper(lut_transform[0], [](size_t x) -> uchar { return 255 - x; } );
      transform_function_helper(lut_transform[1], [](size_t x) -> uchar { return pow((float)x * 255,(1/2.0)); } );
      transform_function_helper(lut_transform[2], [](size_t x) -> uchar { return pow((float)x, 3.0) / (255*255); } );
      /*code*/
    }