Is it possible to get a (n-1)-argument function out of a n-argument function by setting one argument to a fixed value?

StackOverflow https://stackoverflow.com/questions/7848130

  •  10-02-2021
  •  | 
  •  

I was wondering if in C++ it was possible to get a function taking (n-1) arguments out of a function taking n arguments by setting the value for the nth argument to some value (to be determined at runtime)?

E.g. I would like to do something like the following:

float foo(float a, float b, float c){
  // do some stuff
}

float bar(float x, float y, float f(float q, float r)){
  return f(x,y);
}

int main(){
  double (*function)(float, float);
  float some_value;
  // somehow determine some_value, e.g. read from stdin.
  // Now I would like to set function something along the lines of:
  function = foo( . , . , some_value)
  return bar(123, 456, function);
}

Conceptually, foo is a family of functions indexed by c, i.e. a family of functions foo_c (float a, float b) (read "foo_c" as "foo subscript c" here), and I want to pass foo_c respectively a pointer to it as an argument to bar.

Is this possible at all in C++? To the best of my knowledge, this isn't possible with function pointers as above. Is there any other way of doing something like this?

I briefly considered making foo a function template, but this won't work as I want to set it's third argument at runtime.

The obvious solution is of course to amend bar so as to take type float f(float q, float r, float t) as its third argument, but this would make the code a lot less reusable (and seems less elegant). I will want to pass other functions to bar as well, some of which will only take two arguments, more than three, or arguments of different types, which I somehow need to set to a fixed value before passing them to bar.

I haven't quite been able to figure out if I could make bar a template function in this case, along the lines of template <typename T, typename S> float bar(float x, float y, T f(float a, float b, S param), S parameters), and then call it using something like bar <double *(float, float, float), float> (123, 456, function, parameters). Would anything along these lines work at all?

有帮助吗?

解决方案

You cannot do it with function pointers, however, it can be done with function objects. I recommend you look at Boost.Bind if you're using C++03. If you're using C++11, std::bind is part of the standard and works the same way. C++11 also introduces built-in lambdas which do what you're attempting.

For storing the result of bind or a lambda, you can use Boost.Function in C++03 or std::function in C++11.

This example is how you would do it in C++03.

float foo(float a, float b, float c){
  // do some stuff
}

float bar(float x, float y, boost::function<float(float,float)> f){
   return f(x,y);
}

int main(){
  boost::function<float(float,float)> func;
  float some_value;
  // somehow determine some_value, e.g. read from stdin.
  // Now I would like to set function something along the lines of:
  func= boost::bind(foo, _1, _2, some_value);
  return bar(123, 456, func);
}

In C++11, you could use the standardized versions of bind and function, or you could use the lambda feature:

float foo(float a, float b, float c){
  // do some stuff
}

float bar(float x, float y, std::function<float(float,float)> f){
   return f(x,y);
}

int main(){
  std::function<float(float,float)> func;
  float some_value;
  // somehow determine some_value, e.g. read from stdin.
  // Now I would like to set function something along the lines of:
  func= [some_value](float x, float y) { return foo(x,y,some_value); };
  return bar(123, 456, func);
}

其他提示

You can't do it with function pointers like that, but you can do it with function-like objects. C++11 gives you std::bind and std::function (and also lambdas, but I don't know enough about them to give an example); in C++03, boost::bind and boost::function are very similar.

float foo(float a, float b, float c){
  // do some stuff
}

float bar(float x, float y, function<float(float, float)> f){
  return f(x,y);
}

int main(){
  float some_value;
  // somehow determine some_value, e.g. read from stdin.

  return bar(123, 456, bind(foo,_1,_2,some_value));
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top