Boost logo

Boost :

Subject: Re: [boost] [factory][bind] C2664 with MSVC 2015 & 1.63
From: Peter Dimov (lists_at_[hidden])
Date: 2017-02-01 14:34:08

Jens Weller wrote:
> Hi Peter,
> yes, I managed to that by now:
> #include <boost/function.hpp>
> #include <boost/functional/factory.hpp>
> #include <boost/bind.hpp>
> struct Widget {};
> struct Panel: Widget{Panel(Widget* q){}};
> using make_interface = boost::function<Widget*(Widget*)>;
> void registerType(const make_interface &make)
> {
> //factory.register_factory(type_id,make);
> }
> int main(int argc, char *argv[])
> {
> auto f = boost::factory<Panel*>();
> registerType( boost::bind(f,_1));//< this line is the cause, factory
> it self compiles
> }

Thanks Jens.

When I try

    registerType( f );

I get the same error:

1>testbed2015.cpp(6): warning C4100: 'q': unreferenced formal parameter
1>testbed2015.cpp(10): warning C4100: 'make': unreferenced formal parameter
error C2664: 'Panel *boost::factory<Panel
*,void,boost::factory_alloc_for_pointee_and_deleter>::operator ()(void)
const': cannot convert argument 1 from 'Widget *' to 'Widget *&'

The problem as far as I can see is that boost::function passes its parameter
of type Widget* as an rvalue to its target, rather than as an lvalue, and
factory<> takes its arguments by lvalue reference.

function's behavior is correct in that if you declare
boost::function<void(unique_ptr<X>)>, the argument needs to be passed as an
rvalue or it won't work. But it does break code such as the above.

Ideally, boost::factory would need to be fixed to use perfect forwarding on
C++11 and above.

A quick look at its documentation suggests using forward_adapter:

    auto f2 = boost::forward_adapter<decltype(f)>( f );
    registerType( f2 ); // works

forward_adapter however doesn't define ::result_type so when you bind it you
have to give the type:

    registerType( boost::bind<Widget*>( f2, _1 ) );

No idea why it needs to be so hard.

Boost list run by bdawes at, gregod at, cpdaniel at, john at