6

I have a member function as follows:

class XYZ{
public:
    float function(float x);
private:
    float m_DensityMin;
    float m_DensityMax;
};

Now, I'm trying to transform a std::vector<float> foo using the std::transform STL algorithm by passing the member function function, and storing the resulting values in a vector bar.

If I use the function as a global function, with random data that should denote the member variables of the class, it works fine.

However, as the function requires the use of member variables m_DensityMin and m_DensityMax of the class, I need to use it as a member function. This is what I've tried:

std::transform(foo.begin(), foo.end(), bar.begin(), &XYZ::function);

but I end up with the error in VS2010:

error C2065: term does not evaluate to a function taking 1 arguments

As far as I can tell I'm passing only 1 argument. Any pointers? Here's a similar question, I've tried with std::mem_fun, as std::mem_fn is not available to me, but to no avail.

Community
  • 1
  • 1
ccoder83
  • 504
  • 6
  • 15
  • 1
    *"I've tried with std::mem_fun, as std::mem_fn is not available to me, but to no avail."* What problems occurred when using `std::mem_fun`? Have you tried using a lambda? – dyp May 20 '15 at 15:59
  • 1
    Unless it's a static function, you need a parameter object, and bind it to whatever `mem_fun` returns: `std::transform(foo.begin(), foo.end(), std::back_inserter(bar), std::bind1st(std::mem_fun(&XYZ::function), &xyz));`, [demo](http://coliru.stacked-crooked.com/a/1733c6da8b46abee) – Piotr Skotnicki May 20 '15 at 16:01
  • 1
    `function` should probably be a static member function. – David G May 20 '15 at 16:02
  • @ccoder83 VS2010 has `mem_fn`, try `std::tr1::mem_fn` – Praetorian May 20 '15 at 16:07

3 Answers3

9

std::mem_fun itself only povides a wrapper for a member function, so that one will be invoked in the context of the first argument passed to its operator(). Having said that, you need to bind the proper instance of XYZ prior to passing the function object to the std::transform algorithm:

XYZ xyz;

std::transform(foo.begin(), foo.end(),
               std::back_inserter(bar),
               std::bind1st(std::mem_fun(&XYZ::function), &xyz));
//                  ~~~~~~^      ~~~~~~^                  ~~~^

DEMO

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
1

Unless the function is static, it needs an instance of the class to call the function off of. Because non-static functions should depend on the internal state of that class. If the function is independent of the class's state, it should probably be static.

If you had to leave your class as written, you could get around this by default constructing an XYZ just for the purposes of having an instance to call the function from.

std::transform(foo.begin(),
               foo.end(),
               std::back_inserter(bar),
               [](float a){ return XYZ{}.function(a); });

But this feels hacky, I would prefer that the function be static if it isn't dependent on the state of the XYZ instance, and only depends on the input float.

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • `foo` is a `vector`, not `vector`. – David G May 20 '15 at 16:04
  • I like the lambda version much more than std::bind. I actually forgot about std::bind since I learn lambdas and I'm much happier now! I also like the fact that you create the tiny object in place, although it may be better to capture it by reference if its size is relevant. – DarioP May 20 '15 at 16:20
  • 1
    If the function IS dependent on the state of the XYZ instance, you could use a lambda to bind to the same instance of XYZ you called std::transform from. `std::transform(foo.begin(), foo.end(), std::back_inserter(bar), [this](float a){ return this->function(a); })` – Justin Randall Dec 08 '17 at 18:20
0

lambda version

std::vector<float> foo;
std::vector<float> bar;
foo.push_back(1.0f);
foo.push_back(2.0f);
XYZ xyz;
std::transform(foo.begin(), foo.end(), std::back_inserter(bar), 
        [&xyz](float& a){ return xyz.function(a); });
 for ( auto & x : bar)
   std::cout<<x<<"\n";
Steephen
  • 14,645
  • 7
  • 40
  • 47