[{"id":3303,"web_url":"https://patchwork.libcamera.org/comment/3303/","msgid":"<20200103053345.GC3820@localhost.localdomain>","date":"2020-01-03T05:33:45","subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Hi Laurent,\n\nThank you for the patch.\n\nOn Fri, Jan 03, 2020 at 01:53:11AM +0200, Laurent Pinchart wrote:\n> Invoking a method that takes a reference argument with\n> Object::invokeMethod() results in a compilation error:\n> \n> ../test/object-invoke.cpp:131:11: error: no matching member function for call to 'invokeMethod'\n>                 object_.invokeMethod(&InvokedObject::methodWithReference,\n>                 ~~~~~~~~^~~~~~~~~~~~\n> ../include/libcamera/object.h:33:7: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<const int &> vs. <int>)\n>         void invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> \n> This is due to the fact that implicit type conversions (from value to\n> reference in this case) takes place after template argument type\n> deduction, during overload resolution. A similar issue would occur if\n> T::func took a long argument and invokeMethod() was called with an in\n> argument.\n> \n> Fix this by specifying to sets of argument types in the invokeMethod()\n> template, one for the arguments to the invoked method, and one for the\n> arguments to invokeMethod() itself. The compiler can then first perform\n> type deduction separately, and implicit conversion in a second step.\n> \n> Reported-by: Paul Elder <paul.elder@ideasonboard.com>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/object.h | 10 ++++++----\n>  1 file changed, 6 insertions(+), 4 deletions(-)\n> \n> diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> index 86e0f7265865..21b70460b516 100644\n> --- a/include/libcamera/object.h\n> +++ b/include/libcamera/object.h\n> @@ -29,13 +29,15 @@ public:\n>  \n>  \tvoid postMessage(std::unique_ptr<Message> msg);\n>  \n> -\ttemplate<typename T, typename... Args, typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> -\tvoid invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> +\ttemplate<typename T, typename... FuncArgs, typename... Args,\n> +\t\t typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> +\tvoid invokeMethod(void (T::*func)(FuncArgs...), ConnectionType type,\n> +\t\t\t  Args... args)\n>  \t{\n>  \t\tT *obj = static_cast<T *>(this);\n>  \t\tBoundMethodBase *method =\n> -\t\t\tnew BoundMemberMethod<T, Args...>(obj, this, func, type);\n> -\t\tvoid *pack = new typename BoundMemberMethod<T, Args...>::PackType{ args... };\n> +\t\t\tnew BoundMemberMethod<T, FuncArgs...>(obj, this, func, type);\n> +\t\tvoid *pack = new typename BoundMemberMethod<T, FuncArgs...>::PackType{ args... };\n>  \n>  \t\tmethod->activatePack(pack, true);\n>  \t}\n\nOoh, fancy template magic.\n\nLooks good to me.\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>","headers":{"Return-Path":"<paul.elder@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2C99F60462\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Jan 2020 06:33:51 +0100 (CET)","from localhost.localdomain (unknown [96.44.9.94])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 4DC0830F;\n\tFri,  3 Jan 2020 06:33:50 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1578029630;\n\tbh=GOA275GUWMbw5ZDtAIlx4O4qXZCckgfixF0oxkJRoIw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=JkK41IDnChmuCjGFfpqLGrFNou6X5fBADCHdIP04bQaQowz0Kft8dSM1xPi78gjPw\n\tENXdW+NTUfKt7qJbSvJaG1oXI1gqx0juEAU+oNHYj502/LUNWbBGpQUPv/vUAvpqGG\n\ttbaP5OgPxalzrpDYYpbeRC5peB87BXd/JbPpSGk8=","Date":"Fri, 3 Jan 2020 00:33:45 -0500","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200103053345.GC3820@localhost.localdomain>","References":"<20200102235311.12009-1-laurent.pinchart@ideasonboard.com>\n\t<20200102235311.12009-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20200102235311.12009-2-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 03 Jan 2020 05:33:51 -0000"}},{"id":3306,"web_url":"https://patchwork.libcamera.org/comment/3306/","msgid":"<20200103085719.4vbdusqjttojcij7@uno.localdomain>","date":"2020-01-03T08:57:19","subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Fri, Jan 03, 2020 at 01:53:11AM +0200, Laurent Pinchart wrote:\n> Invoking a method that takes a reference argument with\n> Object::invokeMethod() results in a compilation error:\n>\n> ../test/object-invoke.cpp:131:11: error: no matching member function for call to 'invokeMethod'\n>                 object_.invokeMethod(&InvokedObject::methodWithReference,\n>                 ~~~~~~~~^~~~~~~~~~~~\n> ../include/libcamera/object.h:33:7: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<const int &> vs. <int>)\n>         void invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n>\n> This is due to the fact that implicit type conversions (from value to\n> reference in this case) takes place after template argument type\n> deduction, during overload resolution. A similar issue would occur if\n> T::func took a long argument and invokeMethod() was called with an in\n> argument.\n>\n> Fix this by specifying to sets of argument types in the invokeMethod()\n> template, one for the arguments to the invoked method, and one for the\n> arguments to invokeMethod() itself. The compiler can then first perform\n> type deduction separately, and implicit conversion in a second step.\n>\n> Reported-by: Paul Elder <paul.elder@ideasonboard.com>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/object.h | 10 ++++++----\n>  1 file changed, 6 insertions(+), 4 deletions(-)\n>\n> diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> index 86e0f7265865..21b70460b516 100644\n> --- a/include/libcamera/object.h\n> +++ b/include/libcamera/object.h\n> @@ -29,13 +29,15 @@ public:\n>\n>  \tvoid postMessage(std::unique_ptr<Message> msg);\n>\n> -\ttemplate<typename T, typename... Args, typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> -\tvoid invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> +\ttemplate<typename T, typename... FuncArgs, typename... Args,\n> +\t\t typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n\nI'm not sure I got this to the point I can give any tag, could you\nhelp ?\n\nHow does the compiler knows which templates parameters are part of\nFuncArgs and which ones of Args, being the two consecutive ?\n\nThanks\n   j\n\n> +\tvoid invokeMethod(void (T::*func)(FuncArgs...), ConnectionType type,\n> +\t\t\t  Args... args)\n>  \t{\n>  \t\tT *obj = static_cast<T *>(this);\n>  \t\tBoundMethodBase *method =\n> -\t\t\tnew BoundMemberMethod<T, Args...>(obj, this, func, type);\n> -\t\tvoid *pack = new typename BoundMemberMethod<T, Args...>::PackType{ args... };\n> +\t\t\tnew BoundMemberMethod<T, FuncArgs...>(obj, this, func, type);\n> +\t\tvoid *pack = new typename BoundMemberMethod<T, FuncArgs...>::PackType{ args... };\n>\n>  \t\tmethod->activatePack(pack, true);\n>  \t}\n> --\n> Regards,\n>\n> Laurent Pinchart\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net\n\t[217.70.183.193])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9594260464\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Jan 2020 09:55:02 +0100 (CET)","from uno.localdomain\n\t(host109-57-dynamic.61-82-r.retail.telecomitalia.it [82.61.57.109])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay1-d.mail.gandi.net (Postfix) with ESMTPSA id E521324000A;\n\tFri,  3 Jan 2020 08:55:01 +0000 (UTC)"],"X-Originating-IP":"82.61.57.109","Date":"Fri, 3 Jan 2020 09:57:19 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200103085719.4vbdusqjttojcij7@uno.localdomain>","References":"<20200102235311.12009-1-laurent.pinchart@ideasonboard.com>\n\t<20200102235311.12009-2-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"uxsgoox5jrnnbldq\"","Content-Disposition":"inline","In-Reply-To":"<20200102235311.12009-2-laurent.pinchart@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 03 Jan 2020 08:55:02 -0000"}},{"id":3309,"web_url":"https://patchwork.libcamera.org/comment/3309/","msgid":"<20200103112700.GA4847@pendragon.ideasonboard.com>","date":"2020-01-03T11:27:00","subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Fri, Jan 03, 2020 at 09:57:19AM +0100, Jacopo Mondi wrote:\n> On Fri, Jan 03, 2020 at 01:53:11AM +0200, Laurent Pinchart wrote:\n> > Invoking a method that takes a reference argument with\n> > Object::invokeMethod() results in a compilation error:\n> >\n> > ../test/object-invoke.cpp:131:11: error: no matching member function for call to 'invokeMethod'\n> >                 object_.invokeMethod(&InvokedObject::methodWithReference,\n> >                 ~~~~~~~~^~~~~~~~~~~~\n> > ../include/libcamera/object.h:33:7: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<const int &> vs. <int>)\n> >         void invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> >\n> > This is due to the fact that implicit type conversions (from value to\n> > reference in this case) takes place after template argument type\n> > deduction, during overload resolution. A similar issue would occur if\n> > T::func took a long argument and invokeMethod() was called with an in\n> > argument.\n> >\n> > Fix this by specifying to sets of argument types in the invokeMethod()\n> > template, one for the arguments to the invoked method, and one for the\n> > arguments to invokeMethod() itself. The compiler can then first perform\n> > type deduction separately, and implicit conversion in a second step.\n> >\n> > Reported-by: Paul Elder <paul.elder@ideasonboard.com>\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  include/libcamera/object.h | 10 ++++++----\n> >  1 file changed, 6 insertions(+), 4 deletions(-)\n> >\n> > diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> > index 86e0f7265865..21b70460b516 100644\n> > --- a/include/libcamera/object.h\n> > +++ b/include/libcamera/object.h\n> > @@ -29,13 +29,15 @@ public:\n> >\n> >  \tvoid postMessage(std::unique_ptr<Message> msg);\n> >\n> > -\ttemplate<typename T, typename... Args, typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> > -\tvoid invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> > +\ttemplate<typename T, typename... FuncArgs, typename... Args,\n> > +\t\t typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> \n> I'm not sure I got this to the point I can give any tag, could you\n> help ?\n> \n> How does the compiler knows which templates parameters are part of\n> FuncArgs and which ones of Args, being the two consecutive ?\n\nThe first step for the compiler, when encountering a call to\ninvokeMethod() such as\n\n\tobject_.invokeMethod(&InvokedObject::methodWithReference,\n\t\t\t     ConnectionTypeBlocking, 42);\n\nis to perform template argument deduction, as the template arguments are\nnot specified explicitly (compare it to ControlValue::get() where we\nwrite .get<int>() explicitly). With invokeMethod() defined as\n\n\ttemplate<typename T, typename... Args>\n\tvoid invokeMethod(void (T::*func)(Args...), ConnectionType type,\n\t\t\t  Args... args)\n\n(I've left the std::enable_if out for clarity) the compiler thus tries\nto figure out what types T and Args correspond to.\n\nFor T, it's easy. The type is mentioned a single time in the\ninvokeMethod() signature, as void (T::*func)(Args...). The func\nparameter is equal to &InvokedObject::methodWithReference, which is\ndefined as\n\n\tvoid InvokedObject::methodWithReference(const int &value)\n\nT must thus be equal to InvokedObject.\n\nFor Args, the compiler has two sources of information,\nvoid (T::*func)(Args...) and Args... args. For the former, the func\nparameter being equal to &InvokedObject::methodWithReference, the\ncompiler will deduce that Args... is equal to const int &. For the\nlatter, the compiler looks at the parameters passed to invokeMethod()\nafter the first two, and finds 42, which is of type int. It thus deduces\nthat Args... is equal to int. The two deductions don't match,\ncompilation fails.\n\nWith the new version of invokeMethod() defined as \n\n\ttemplate<typename T, typename... FuncArgs, typename... Args>\n\tvoid invokeMethod(void (T::*func)(FuncArgs...), ConnectionType type,\n\t\t\t  Args... args)\n\nthe compiler will deduce T to InvokedObject, FuncArgs... to const int &\nand Args... to int. There's no conflict anymore, this compilation step\nsucceeds.\n\nIn invokeMethod(), the compiler then encounters\n\n\tvoid *pack = new typename BoundMemberMethod<T, FuncArgs...>::PackType{ args... };\n\nBoundMemberMethod::PackType is defined as\n\n\tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n\nwhich in this case is\n\n\tstd::tuple<typename std::remove_reference<FuncArgs>::type...>\n\tstd::tuple<typename std::remove_reference<const int &>::type>\n\tstd::tuple<const int>\n\nresulting in\n\n\tvoid *pack = new std::tuple<const int>{ args... };\n\nargs is an int, so this succeeds. Note that if args was an int & this\nwould succeed as well, as the compiler would perform implicit conversion\nfrom reference to value. If the types were incompatible, for instance if\nthe test called\n\n\tobject_.invokeMethod(&InvokedObject::methodWithReference,\n\t\t\t     ConnectionTypeBlocking, \"foo\");\n\nthe compiler would still complain that a const char * can't be\nimplicitly converted to an int. This patch doesn't remove all compiler\nsafety checks, it only relaxes the constraints on template argument\ndeduction.\n\n> > +\tvoid invokeMethod(void (T::*func)(FuncArgs...), ConnectionType type,\n> > +\t\t\t  Args... args)\n> >  \t{\n> >  \t\tT *obj = static_cast<T *>(this);\n> >  \t\tBoundMethodBase *method =\n> > -\t\t\tnew BoundMemberMethod<T, Args...>(obj, this, func, type);\n> > -\t\tvoid *pack = new typename BoundMemberMethod<T, Args...>::PackType{ args... };\n> > +\t\t\tnew BoundMemberMethod<T, FuncArgs...>(obj, this, func, type);\n> > +\t\tvoid *pack = new typename BoundMemberMethod<T, FuncArgs...>::PackType{ args... };\n> >\n> >  \t\tmethod->activatePack(pack, true);\n> >  \t}","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9273F60465\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Jan 2020 12:27:11 +0100 (CET)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 0650830F;\n\tFri,  3 Jan 2020 12:27:10 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1578050831;\n\tbh=ChME7dAPEk7IVvw0oaJl5ymo0YIhpKh76IzRhN37EaM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=lqc3/bt9M12wN+92WYYLDuQmYFZ06JH9TOhmW2bOS6ZR0SXCzigEKUXQQ9vXd9tn0\n\tS63X2PesJ1P0hqK96fxRdCEMTIBjqg2KhLZFMecviLOXhz79d1wW/EIVLcb1PxqtCy\n\tZ1h+kRQGhrUxwYohVhaFZZhAEfptSECbzqgdqMGk=","Date":"Fri, 3 Jan 2020 13:27:00 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200103112700.GA4847@pendragon.ideasonboard.com>","References":"<20200102235311.12009-1-laurent.pinchart@ideasonboard.com>\n\t<20200102235311.12009-2-laurent.pinchart@ideasonboard.com>\n\t<20200103085719.4vbdusqjttojcij7@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20200103085719.4vbdusqjttojcij7@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 03 Jan 2020 11:27:11 -0000"}},{"id":3314,"web_url":"https://patchwork.libcamera.org/comment/3314/","msgid":"<20200103142529.nm2fqp4k6cb6abi6@uno.localdomain>","date":"2020-01-03T14:25:29","subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Fri, Jan 03, 2020 at 01:27:00PM +0200, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> On Fri, Jan 03, 2020 at 09:57:19AM +0100, Jacopo Mondi wrote:\n> > On Fri, Jan 03, 2020 at 01:53:11AM +0200, Laurent Pinchart wrote:\n> > > Invoking a method that takes a reference argument with\n> > > Object::invokeMethod() results in a compilation error:\n> > >\n> > > ../test/object-invoke.cpp:131:11: error: no matching member function for call to 'invokeMethod'\n> > >                 object_.invokeMethod(&InvokedObject::methodWithReference,\n> > >                 ~~~~~~~~^~~~~~~~~~~~\n> > > ../include/libcamera/object.h:33:7: note: candidate template ignored: deduced conflicting types for parameter 'Args' (<const int &> vs. <int>)\n> > >         void invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> > >\n> > > This is due to the fact that implicit type conversions (from value to\n> > > reference in this case) takes place after template argument type\n> > > deduction, during overload resolution. A similar issue would occur if\n> > > T::func took a long argument and invokeMethod() was called with an in\n> > > argument.\n> > >\n> > > Fix this by specifying to sets of argument types in the invokeMethod()\n> > > template, one for the arguments to the invoked method, and one for the\n> > > arguments to invokeMethod() itself. The compiler can then first perform\n> > > type deduction separately, and implicit conversion in a second step.\n> > >\n> > > Reported-by: Paul Elder <paul.elder@ideasonboard.com>\n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > ---\n> > >  include/libcamera/object.h | 10 ++++++----\n> > >  1 file changed, 6 insertions(+), 4 deletions(-)\n> > >\n> > > diff --git a/include/libcamera/object.h b/include/libcamera/object.h\n> > > index 86e0f7265865..21b70460b516 100644\n> > > --- a/include/libcamera/object.h\n> > > +++ b/include/libcamera/object.h\n> > > @@ -29,13 +29,15 @@ public:\n> > >\n> > >  \tvoid postMessage(std::unique_ptr<Message> msg);\n> > >\n> > > -\ttemplate<typename T, typename... Args, typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> > > -\tvoid invokeMethod(void (T::*func)(Args...), ConnectionType type, Args... args)\n> > > +\ttemplate<typename T, typename... FuncArgs, typename... Args,\n> > > +\t\t typename std::enable_if<std::is_base_of<Object, T>::value>::type * = nullptr>\n> >\n> > I'm not sure I got this to the point I can give any tag, could you\n> > help ?\n> >\n> > How does the compiler knows which templates parameters are part of\n> > FuncArgs and which ones of Args, being the two consecutive ?\n>\n> The first step for the compiler, when encountering a call to\n> invokeMethod() such as\n>\n> \tobject_.invokeMethod(&InvokedObject::methodWithReference,\n> \t\t\t     ConnectionTypeBlocking, 42);\n>\n> is to perform template argument deduction, as the template arguments are\n> not specified explicitly (compare it to ControlValue::get() where we\n> write .get<int>() explicitly). With invokeMethod() defined as\n>\n> \ttemplate<typename T, typename... Args>\n> \tvoid invokeMethod(void (T::*func)(Args...), ConnectionType type,\n> \t\t\t  Args... args)\n>\n> (I've left the std::enable_if out for clarity) the compiler thus tries\n> to figure out what types T and Args correspond to.\n>\n> For T, it's easy. The type is mentioned a single time in the\n> invokeMethod() signature, as void (T::*func)(Args...). The func\n> parameter is equal to &InvokedObject::methodWithReference, which is\n> defined as\n>\n> \tvoid InvokedObject::methodWithReference(const int &value)\n>\n> T must thus be equal to InvokedObject.\n>\n> For Args, the compiler has two sources of information,\n> void (T::*func)(Args...) and Args... args. For the former, the func\n> parameter being equal to &InvokedObject::methodWithReference, the\n> compiler will deduce that Args... is equal to const int &. For the\n> latter, the compiler looks at the parameters passed to invokeMethod()\n> after the first two, and finds 42, which is of type int. It thus deduces\n> that Args... is equal to int. The two deductions don't match,\n> compilation fails.\n>\n> With the new version of invokeMethod() defined as\n>\n> \ttemplate<typename T, typename... FuncArgs, typename... Args>\n> \tvoid invokeMethod(void (T::*func)(FuncArgs...), ConnectionType type,\n> \t\t\t  Args... args)\n>\n> the compiler will deduce T to InvokedObject, FuncArgs... to const int &\n> and Args... to int. There's no conflict anymore, this compilation step\n> succeeds.\n>\n> In invokeMethod(), the compiler then encounters\n>\n> \tvoid *pack = new typename BoundMemberMethod<T, FuncArgs...>::PackType{ args... };\n>\n> BoundMemberMethod::PackType is defined as\n>\n> \tusing PackType = std::tuple<typename std::remove_reference<Args>::type...>;\n>\n> which in this case is\n>\n> \tstd::tuple<typename std::remove_reference<FuncArgs>::type...>\n> \tstd::tuple<typename std::remove_reference<const int &>::type>\n> \tstd::tuple<const int>\n>\n> resulting in\n>\n> \tvoid *pack = new std::tuple<const int>{ args... };\n>\n> args is an int, so this succeeds. Note that if args was an int & this\n> would succeed as well, as the compiler would perform implicit conversion\n> from reference to value. If the types were incompatible, for instance if\n> the test called\n>\n> \tobject_.invokeMethod(&InvokedObject::methodWithReference,\n> \t\t\t     ConnectionTypeBlocking, \"foo\");\n>\n> the compiler would still complain that a const char * can't be\n> implicitly converted to an int. This patch doesn't remove all compiler\n> safety checks, it only relaxes the constraints on template argument\n> deduction.\n>\n\nThanks, very clear and informative!\nPlease have my\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nand saved in my \"how to deal with C++ preserving your remaining\nsanity\" notes\n\nThanks\n   j\n\n> > > +\tvoid invokeMethod(void (T::*func)(FuncArgs...), ConnectionType type,\n> > > +\t\t\t  Args... args)\n> > >  \t{\n> > >  \t\tT *obj = static_cast<T *>(this);\n> > >  \t\tBoundMethodBase *method =\n> > > -\t\t\tnew BoundMemberMethod<T, Args...>(obj, this, func, type);\n> > > -\t\tvoid *pack = new typename BoundMemberMethod<T, Args...>::PackType{ args... };\n> > > +\t\t\tnew BoundMemberMethod<T, FuncArgs...>(obj, this, func, type);\n> > > +\t\tvoid *pack = new typename BoundMemberMethod<T, FuncArgs...>::PackType{ args... };\n> > >\n> > >  \t\tmethod->activatePack(pack, true);\n> > >  \t}\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net\n\t[217.70.183.200])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6146060466\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Jan 2020 15:23:18 +0100 (CET)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay7-d.mail.gandi.net (Postfix) with ESMTPSA id F385320007;\n\tFri,  3 Jan 2020 14:23:16 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Fri, 3 Jan 2020 15:25:29 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200103142529.nm2fqp4k6cb6abi6@uno.localdomain>","References":"<20200102235311.12009-1-laurent.pinchart@ideasonboard.com>\n\t<20200102235311.12009-2-laurent.pinchart@ideasonboard.com>\n\t<20200103085719.4vbdusqjttojcij7@uno.localdomain>\n\t<20200103112700.GA4847@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"3wrnv2byulewizys\"","Content-Disposition":"inline","In-Reply-To":"<20200103112700.GA4847@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 2/2] libcamera: object: Support\n\treference arguments in invokeMethod()","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 03 Jan 2020 14:23:18 -0000"}}]