2

I have the following code which compiles and runs fine under Visual Studio 2008 SP1.

#include <functional>
#include <iostream>

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>

class NoncopyableObject : public boost::noncopyable
{
public:
    NoncopyableObject(int x) : x_(x) {}
    int getValue() const {return x_;}
private:
    int x_;
};

template<class F>
class MenuItemDispatcher
{
public:
    MenuItemDispatcher(F f) : f_(f) { }

    void operator ()(NoncopyableObject& w) const
    {
        // Invoke the functor
        f_(w);
    }
private:
    typedef boost::function1<void,NoncopyableObject&> FUNC;
    FUNC f_;
};

void MenuItem()
{
    std::cout << "in MenuItem()\n";
}

template<class F>
MenuItemDispatcher<F> MakeMenuItemDispatcher(F f)
{
    return MenuItemDispatcher<F>(f);
}

int main()
{
    NoncopyableObject obj(7);
    MakeMenuItemDispatcher(boost::bind(&MenuItem))(obj);
}

If I change the boost::bind to std::tr1::bind in main(), I get an error:

error C2248: 'boost::noncopyable_::noncopyable::noncopyable' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'.

This diagnostic occurred in the compiler generated function 'NoncopyableObject::NoncopyableObject(const NoncopyableObject &)'

So it's trying to generate a copy constructor for NoncopyableObject. Anyone know why this might be so please? MenuItemDispatcher's call operator takes a reference to a NoncopyableObject, so I am struggling to see what's going wrong.

Community
  • 1
  • 1
PeteUK
  • 1,062
  • 12
  • 26
  • Do you get the same error if you break that last line into two lines? I'm thinking one line to declare the `MakeMenuItemDispatcher` and one to call it. Just trying to rule out some weird parsing issue with the code as it is now. – Michael Kristofik Jul 11 '11 at 17:36
  • works in gcc 4.4.1, 4.5.2, fails in VS 2010 SP1. To reproduce, it's sufficient to attempt to create a boost/std function that takes `Noncopyable&` from a boost/std bind that doesn't – Cubbi Jul 11 '11 at 17:46

1 Answers1

4

This appears to be a difference in how bind is implemented in MS Visual Studio (including 2010) and GNU gcc (I tested 4.4.1 and 4.5.2, both of which work the way you expected)

Consider the following code, given your definitions

auto b = boost::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj);  // OK in VS and GCC

replacing boost::bind with std::bind (I'm using 2010, the error message appears to be the same as in your 2008)

auto b = std::bind(&MenuItem);
NoncopyableObject obj(7);
b(obj);  // compile error in VS 2010 SP1, OK in GCC
b(std::reference_wrapper<NoncopyableObject>(obj)); // OK in both

So, what happens is that MS's bind() makes a copy of its argument even if the argument is not going to be used, while boost's and GCC's bind() does not bother with that argument at all.

I was able to get your example to compile and run (on 2010) by changing the FUNC typedef to

typedef boost::function1<void, std::tr1::reference_wrapper<NoncopyableObject> > FUNC;
Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • thank you so much for this. Employing reference_wrapper does the trick. I think there's one slight error in your answer: the line of code b(std::reference_wrapper(obj)); // OK in both should be using std::ref (or std::tr1::ref) instead I think? – PeteUK Jul 12 '11 at 07:41
  • @PUK You're right, using the `ref()` helper function when making the function call is a bit easier to read. It's the same as using make_pair(arg1, arg2) instead of pair(arg1, arg2); – Cubbi Jul 12 '11 at 12:56
  • How silly of me. Of course - it's going via a function for with template argument deduction. Thanks! – PeteUK Jul 13 '11 at 09:22