Tuesday, March 1, 2011

How do I use std::tr1::mem_fun in Visual Studio 2008 SP1?

The VS2008 SP1 documentation talks about std::tr1::mem_fun.

So why, when I try and use std::tr1::mem_fun, why do I get this compile error?:

'mem_fun' : is not a member of 'std::tr1'

At the same time, I can use std::tr1::function without problems.

Here is the sample code I am trying to compile, which is supposed to call TakesInt on an instance of Test, via a function<void (int)>:

#include "stdafx.h"
#include <iostream>
#include <functional>
#include <memory>

struct Test { void TakesInt(int i) { std::cout << i; } };

void _tmain() 
{
    Test* t = new Test();

    //error C2039: 'mem_fun' : is not a member of 'std::tr1'
    std::tr1::function<void (int)> f =
        std::tr1::bind(std::tr1::mem_fun(&Test::TakesInt), t);
    f(2);
}

I'm trying to use the tr1 version of mem_fun, because when using std::mem_fun my code doesn't compile either! I can't tell from the compiler error whether the problem is with my code or whether it would be fixed by using tr1's mem_fun. That's C++ compiler errors for you (or maybe it's just me!).


Update: Right. The answer is to spell it correctly as mem_fn!

However when I fix that, the code still doesn't compile.

Here's the compiler error:

error C2562: 
'std::tr1::_Callable_obj<_Ty,_Indirect>::_ApplyX' :
  'void' function returning a value
From stackoverflow
  • I am no expert on either TR1 or VS2008, but a quick googling suggests that the function you're looking for is std::tr1::mem_fn instead. (At least, that's what Boost calls it in their TR1 implementation, and that's how it's detailed on Wikipedia.)

    I'm not sure why you're getting a compile error with the old version of mem_fun though. If you post the compiler's message about that, it might help us figure it out.

  • To use mem_fun like that you need to fully specify all the template arguments (as mem_fun is a class and automatic template parameter deduction is not done on classes). Also mem_fun only has a default constructor that takes 0 arguments.

    Not having the full class definition it is hard to get correct.
    But my best bet at what you wanted would be this: (or something close)

     std::tr1::mem_fun<Test,void (Test::*)(Test*),&Test::TakesInt>()
    

    What I think you are looking for is mem_fn(). This is a function that returns an object of type mem_fun. Because it is a function automatic template parameter deduction is done.

      std::tr1::mem_fn(&Test::TakesInt)
    

    To solve the second problem use: std::bind1st()

      f=    std::bind1st(std::tr1::mem_fn(&Test::TakesInt), t);
    
    mackenir : struct Test is fully defined in the sample code. I've updated the question with the compiler error I get when I use mem_fn.
  • Change it to this:

    std::tr1::function<void (int)> f =
        std::tr1::bind(std::tr1::mem_fn(&Test::TakesInt), t, std::tr1::placeholders::_1);
    f(2);
    

    The binder requires the int argument. So you have to give it a placeholder which stands for the integer argument that the generated function object needs.

    Btw: I'm not sure whether you already know this or not. But you don't need that mem_fn for this. Just change it to

    std::tr1::function<void (int)> f =
        std::tr1::bind(&Test::TakesInt, t, std::tr1::placeholders::_1);
    f(2);
    
    mackenir : Thanks! I had just worked out where _1 came from and was coming back to update my question with the fix.
    mackenir : Okay, all answers got me nearer to a solution, so I had trouble picking which one to accept. But unfortunately I can only accept one. I think this one shows the cleanest way to implement what I want, using the tr1 additions, but I up-voted all others. Thanks all.

0 comments:

Post a Comment