[factory][bind] C2664 with MSVC 2015 & 1.63

Hello Boost, I'm having this Problem: http://lists.boost.org/boost-users/2015/04/84176.php That message already describes pretty much what I see, except that I use 1.63 and the latest 2015 VC++. Errormessage: D:\cpp\libraries\boost_1_63_0\boost\bind\bind.hpp:388: error: C2664: 'ListsModuleWidget *boost::factory<ListsModuleWidget *,void,boost::factory_alloc_for_pointee_and_deleter>::operator ()(void) const': cannot convert argument 1 from 'Module *' to 'Module *&' bind.hpp code:
template<class R, class F, class A> R operator()(type<R>, F & f, A & a, long) {
this line return unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_]); }
Compiler says: ..\..\..\..\cpp\libraries\boost_1_63_0\boost/bind/bind.hpp(388): error C2664: 'ListsModuleWidget *boost::factory<ListsModuleWidget *,void,boost::factory_alloc_for_pointee_and_deleter>::operator ()(void) const': cannot convert argument 1 from 'Module *' to 'Module *&' ..\..\..\..\cpp\libraries\boost_1_63_0\boost/bind/bind.hpp(1342): note: see reference to function template instantiation 'R *boost::_bi::list3<boost::arg<1>,boost::arg<2>,boost::arg<3>>::operator ()<ListsModuleWidget*,F,boost::_bi::rrlist4<A1,A2,A3,A4>>(boost::_bi::type<ListsModuleWidget *>,F &,A &,long)' being compiled with [ R=ListsModuleWidget *, F=boost::factory<ListsModuleWidget *,void,boost::factory_alloc_for_pointee_and_deleter>, A1=Module *, A2=const QString &, A3=const QString &, A4=QWidget *, A=boost::_bi::rrlist4<Module *,const QString &,const QString &,QWidget *> ] cheers, Jens Weller

Jens Weller wrote:
Hello Boost,
I'm having this Problem: http://lists.boost.org/boost-users/2015/04/84176.php
That message already describes pretty much what I see, except that I use 1.63 and the latest 2015 VC++.
Can you please give me a short but complete program that fails with the same or a similar error?

Gesendet: Mittwoch, 01. Februar 2017 um 17:04 Uhr Von: "Peter Dimov" <lists@pdimov.com> An: boost@lists.boost.org Betreff: Re: [boost] [factory][bind] C2664 with MSVC 2015 & 1.63
Jens Weller wrote:
Hello Boost,
I'm having this Problem: http://lists.boost.org/boost-users/2015/04/84176.php
That message already describes pretty much what I see, except that I use 1.63 and the latest 2015 VC++.
Can you please give me a short but complete program that fails with the same or a similar error?
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
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 } Error: boost\bind\bind.hpp:249: 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 *&' thanks, Jens Weller Adding the full error message from compiler output here: D:\cpp\libraries\boost_1_63_0\boost/bind/bind.hpp(249): 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 *&' D:\cpp\libraries\boost_1_63_0\boost/bind/bind.hpp(1306): note: see reference to function template instantiation 'R *boost::_bi::list1<boost::arg<1>>::operator ()<Panel*,F,boost::_bi::rrlist1<A1>>(boost::_bi::type<Panel *>,F &,A &,long)' being compiled with [ R=Panel *, F=boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>, A1=Widget *, A=boost::_bi::rrlist1<Widget *> ] D:\cpp\libraries\boost_1_63_0\boost/bind/bind.hpp(1306): note: see reference to function template instantiation 'R *boost::_bi::list1<boost::arg<1>>::operator ()<Panel*,F,boost::_bi::rrlist1<A1>>(boost::_bi::type<Panel *>,F &,A &,long)' being compiled with [ R=Panel *, F=boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>, A1=Widget *, A=boost::_bi::rrlist1<Widget *> ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(138): note: see reference to function template instantiation 'Panel *boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>::operator ()<T>(A1 &&)' being compiled with [ T=Widget *, A1=Widget * ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(138): note: see reference to function template instantiation 'Panel *boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>::operator ()<T>(A1 &&)' being compiled with [ T=Widget *, A1=Widget * ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(132): note: while compiling class template member function 'Widget *boost::detail::function::function_obj_invoker1<FunctionObj,R,T0>::invoke(boost::detail::function::function_buffer &,T0)' with [ FunctionObj=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>, R=Widget *, T0=Widget * ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(936): note: see reference to function template instantiation 'Widget *boost::detail::function::function_obj_invoker1<FunctionObj,R,T0>::invoke(boost::detail::function::function_buffer &,T0)' being compiled with [ FunctionObj=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>, R=Widget *, T0=Widget * ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(936): note: see reference to class template instantiation 'boost::detail::function::function_obj_invoker1<FunctionObj,R,T0>' being compiled with [ FunctionObj=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>, R=Widget *, T0=Widget * ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(727): note: see reference to function template instantiation 'void boost::function1<R,T0>::assign_to<Functor>(Functor)' being compiled with [ R=Widget *, T0=Widget *, Functor=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>> ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(727): note: see reference to function template instantiation 'void boost::function1<R,T0>::assign_to<Functor>(Functor)' being compiled with [ R=Widget *, T0=Widget *, Functor=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>> ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(1073): note: see reference to function template instantiation 'boost::function1<R,T0>::function1<Functor>(Functor,int)' being compiled with [ R=Widget *, T0=Widget *, Functor=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>> ] D:\cpp\libraries\boost_1_63_0\boost/function/function_template.hpp(1072): note: see reference to function template instantiation 'boost::function1<R,T0>::function1<Functor>(Functor,int)' being compiled with [ R=Widget *, T0=Widget *, Functor=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>> ] ..\msvctestbed\main.cpp(19): note: see reference to function template instantiation 'boost::function<Widget *(Widget *)>::function<boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>>(Functor,int)' being compiled with [ Functor=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>> ] ..\msvctestbed\main.cpp(19): note: see reference to function template instantiation 'boost::function<Widget *(Widget *)>::function<boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>>>(Functor,int)' being compiled with [ Functor=boost::_bi::bind_t<boost::_bi::unspecified,boost::factory<Panel *,void,boost::factory_alloc_for_pointee_and_deleter>,boost::_bi::list1<boost::arg<1>>> ]

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 1>c:\Projects\boost-git\boost\boost/function/function_template.hpp(138): 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.

Gesendet: Mittwoch, 01. Februar 2017 um 20:34 Uhr Von: "Peter Dimov" <lists@pdimov.com> An: boost@lists.boost.org Betreff: Re: [boost] [factory][bind] C2664 with MSVC 2015 & 1.63
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 1>c:\Projects\boost-git\boost\boost/function/function_template.hpp(138): 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.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Yes, that fixes this indeed. Didn't know about forward_adapter. thanks, Jens Weller
participants (2)
-
Jens Weller
-
Peter Dimov