[{"id":38352,"web_url":"https://patchwork.libcamera.org/comment/38352/","msgid":"<14ba62e2-38a9-43df-89d4-2a27b4c85272@ideasonboard.com>","date":"2026-03-13T13:57:34","subject":"Re: [PATCH v4 2/7] libcamera: utils: Add overloaded visitor helpers","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 03. 13. 12:33 keltezéssel, Jacopo Mondi írta:\n> std::visit() allows quite elegant type-matching implementation of the\n> visitor pattern.\n> \n> The overaloded type helpers allow to define a hierarchy of overloaded\n      'overloaded'\n\n\n> operator() implementations which can be used by std::visit().\n> \n> Currently only the Virtual pipeline handler uses this type-matching\n> implementation of std::visit. To prepare to add another user in the Mali\n> C55 pipeline handler move the 'overloaded' helper types to\n                                                     type\n\n\n> libcamera::utils for easier re-use.\n> \n> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> ---\n>   include/libcamera/base/utils.h             |  7 ++++++\n>   src/libcamera/base/utils.cpp               | 35 ++++++++++++++++++++++++++++++\n>   src/libcamera/pipeline/virtual/virtual.cpp | 10 ++-------\n>   3 files changed, 44 insertions(+), 8 deletions(-)\n> \n> diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h\n> index 7083b7ce9ce9..62c7f89c25a1 100644\n> --- a/include/libcamera/base/utils.h\n> +++ b/include/libcamera/base/utils.h\n> @@ -37,6 +37,13 @@ namespace libcamera {\n>   \n>   namespace utils {\n>   \n> +template<class... Ts>\n> +struct overloaded : Ts... {\n> +\tusing Ts::operator()...;\n> +};\n> +template<class... Ts>\n> +overloaded(Ts...) -> overloaded<Ts...>;\n> +\n>   const char *basename(const char *path);\n>   \n>   char *secure_getenv(const char *name);\n> diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp\n> index 42a516097be2..a18ca82e8d07 100644\n> --- a/src/libcamera/base/utils.cpp\n> +++ b/src/libcamera/base/utils.cpp\n> @@ -23,6 +23,41 @@ namespace libcamera {\n>   \n>   namespace utils {\n>   \n> +/**\n> + * \\struct overloaded\n> + * \\brief Helper type for type-matching std::visit implementations\n> + * \\tparam Ts... Template arguments pack of visitors\n> + *\n> + * Expand the template argument pack \\a Ts... to provide overloaded\n> + * implementations of \\a operator().\n> + */\n> +\n> +/**\n> + * \\var <class... Ts> overloaded(Ts...) -> overloaded<Ts...>\n\nThis is just a deduction guide. Does doxygen fail if it is not documented? In any case,\nif documented, I think it should just mention that this is a deduction guide necessary\nfor C++17. And the below text should be moved to the documentation of the type itself.\n\nReviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\n\n> + * \\brief Overloaded visitor class for type-matching std::visit implementations\n> + * \\tparam Ts... Template arguments pack of visitor functions\n> + *\n> + * std::visit allows quite elegant type-matching implementation of the visitor\n> + * pattern. An example is provided by the STL documentation in the form of:\n> + *\n> + * \\code{.cpp}\n> + * template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };\n> + * template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;\n> + *\n> + * using var_t = std::variant<int, long, double, std::string>;\n> + * std::vector<var_t> vec = {10, 15l, 1.5, \"hello\"};\n> + *\n> + * for (auto& v: vec) {\n> + * \tstd::visit(overloaded {\n> + * \t\t[](auto arg) { std::cout << arg << ' '; },\n> + * \t\t[](double arg) { std::cout << std::fixed << arg << ' '; },\n> + * \t\t[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },\n> + * \t}, v);\n> + * \\endcode\n> + *\n> + * Use this helper to implement type-matching visitors using std::visit().\n> + */\n> +\n>   /**\n>    * \\brief Strip the directory prefix from the path\n>    * \\param[in] path The path to process\n> diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\n> index efd800ebe3d6..e8ef7e524ccf 100644\n> --- a/src/libcamera/pipeline/virtual/virtual.cpp\n> +++ b/src/libcamera/pipeline/virtual/virtual.cpp\n> @@ -23,6 +23,7 @@\n>   \n>   #include <libcamera/base/flags.h>\n>   #include <libcamera/base/log.h>\n> +#include <libcamera/base/utils.h>\n>   \n>   #include <libcamera/control_ids.h>\n>   #include <libcamera/controls.h>\n> @@ -57,13 +58,6 @@ uint64_t currentTimestamp()\n>   \n>   } /* namespace */\n>   \n> -template<class... Ts>\n> -struct overloaded : Ts... {\n> -\tusing Ts::operator()...;\n> -};\n> -template<class... Ts>\n> -overloaded(Ts...) -> overloaded<Ts...>;\n> -\n>   class VirtualCameraConfiguration : public CameraConfiguration\n>   {\n>   public:\n> @@ -428,7 +422,7 @@ bool PipelineHandlerVirtual::initFrameGenerator(Camera *camera)\n>   {\n>   \tauto data = cameraData(camera);\n>   \tauto &frame = data->config_.frame;\n> -\tstd::visit(overloaded{\n> +\tstd::visit(utils::overloaded{\n>   \t\t\t   [&](TestPattern &testPattern) {\n>   \t\t\t\t   for (auto &streamConfig : data->streamConfigs_) {\n>   \t\t\t\t\t   if (testPattern == TestPattern::DiagonalLines)\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 82AE2BDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Mar 2026 13:57:41 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 709CA6261B;\n\tFri, 13 Mar 2026 14:57:40 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 91F926261B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Mar 2026 14:57:38 +0100 (CET)","from [192.168.33.26] (185.182.214.153.nat.pool.zt.hu\n\t[185.182.214.153])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 39A8F46F;\n\tFri, 13 Mar 2026 14:56:29 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"La22Xxcu\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1773410189;\n\tbh=xO5IacdT4XxXYXOOeWNnEh3P4+hPUgrTMEqvD9lmVZY=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=La22XxcuAd9+BxbmU0H4/Zd+Loih36KIVwGt/1f/l1e8Nq0dq/8XQL1UGzL3H/p/S\n\tYaBjAEPiltl0++wDmGxAE36yJG1VwOQKJkVsRxaZUxriWHOvwrH0UF2Bn1KyhTKfIs\n\tWSkRG5i9DTE1lUaM+kAjr+vV/cskKBR6LuqYKQM8=","Message-ID":"<14ba62e2-38a9-43df-89d4-2a27b4c85272@ideasonboard.com>","Date":"Fri, 13 Mar 2026 14:57:34 +0100","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v4 2/7] libcamera: utils: Add overloaded visitor helpers","To":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>,\n\tDaniel Scally <dan.scally@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20260313-mali-cru-v4-0-c0d9bc8cd8fa@ideasonboard.com>\n\t<20260313-mali-cru-v4-2-c0d9bc8cd8fa@ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260313-mali-cru-v4-2-c0d9bc8cd8fa@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":38356,"web_url":"https://patchwork.libcamera.org/comment/38356/","msgid":"<abQlsu39Z9lhNP2-@zed>","date":"2026-03-13T15:04:31","subject":"Re: [PATCH v4 2/7] libcamera: utils: Add overloaded visitor helpers","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"On Fri, Mar 13, 2026 at 02:57:34PM +0100, Barnabás Pőcze wrote:\n> 2026. 03. 13. 12:33 keltezéssel, Jacopo Mondi írta:\n> > std::visit() allows quite elegant type-matching implementation of the\n> > visitor pattern.\n> >\n> > The overaloded type helpers allow to define a hierarchy of overloaded\n>      'overloaded'\n>\n>\n> > operator() implementations which can be used by std::visit().\n> >\n> > Currently only the Virtual pipeline handler uses this type-matching\n> > implementation of std::visit. To prepare to add another user in the Mali\n> > C55 pipeline handler move the 'overloaded' helper types to\n>                                                     type\n>\n>\n> > libcamera::utils for easier re-use.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > ---\n> >   include/libcamera/base/utils.h             |  7 ++++++\n> >   src/libcamera/base/utils.cpp               | 35 ++++++++++++++++++++++++++++++\n> >   src/libcamera/pipeline/virtual/virtual.cpp | 10 ++-------\n> >   3 files changed, 44 insertions(+), 8 deletions(-)\n> >\n> > diff --git a/include/libcamera/base/utils.h b/include/libcamera/base/utils.h\n> > index 7083b7ce9ce9..62c7f89c25a1 100644\n> > --- a/include/libcamera/base/utils.h\n> > +++ b/include/libcamera/base/utils.h\n> > @@ -37,6 +37,13 @@ namespace libcamera {\n> >   namespace utils {\n> > +template<class... Ts>\n> > +struct overloaded : Ts... {\n> > +\tusing Ts::operator()...;\n> > +};\n> > +template<class... Ts>\n> > +overloaded(Ts...) -> overloaded<Ts...>;\n> > +\n> >   const char *basename(const char *path);\n> >   char *secure_getenv(const char *name);\n> > diff --git a/src/libcamera/base/utils.cpp b/src/libcamera/base/utils.cpp\n> > index 42a516097be2..a18ca82e8d07 100644\n> > --- a/src/libcamera/base/utils.cpp\n> > +++ b/src/libcamera/base/utils.cpp\n> > @@ -23,6 +23,41 @@ namespace libcamera {\n> >   namespace utils {\n> > +/**\n> > + * \\struct overloaded\n> > + * \\brief Helper type for type-matching std::visit implementations\n> > + * \\tparam Ts... Template arguments pack of visitors\n> > + *\n> > + * Expand the template argument pack \\a Ts... to provide overloaded\n> > + * implementations of \\a operator().\n> > + */\n> > +\n> > +/**\n> > + * \\var <class... Ts> overloaded(Ts...) -> overloaded<Ts...>\n>\n> This is just a deduction guide. Does doxygen fail if it is not documented? In any case,\n\nIt's pretty easy to test: yes, it does\ninclude/libcamera/base/utils.h:45: warning: Member overloaded(Ts...) -> overloaded< Ts... > (function) of namespace libcamera::utils is not documented.\n\n> if documented, I think it should just mention that this is a deduction guide necessary\n> for C++17. And the below text should be moved to the documentation of the type itself.\n>\n\nI'll move the documentation!\n\n> Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n\nThanks\n  j\n\n>\n>\n> > + * \\brief Overloaded visitor class for type-matching std::visit implementations\n> > + * \\tparam Ts... Template arguments pack of visitor functions\n> > + *\n> > + * std::visit allows quite elegant type-matching implementation of the visitor\n> > + * pattern. An example is provided by the STL documentation in the form of:\n> > + *\n> > + * \\code{.cpp}\n> > + * template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };\n> > + * template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;\n> > + *\n> > + * using var_t = std::variant<int, long, double, std::string>;\n> > + * std::vector<var_t> vec = {10, 15l, 1.5, \"hello\"};\n> > + *\n> > + * for (auto& v: vec) {\n> > + * \tstd::visit(overloaded {\n> > + * \t\t[](auto arg) { std::cout << arg << ' '; },\n> > + * \t\t[](double arg) { std::cout << std::fixed << arg << ' '; },\n> > + * \t\t[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },\n> > + * \t}, v);\n> > + * \\endcode\n> > + *\n> > + * Use this helper to implement type-matching visitors using std::visit().\n> > + */\n> > +\n> >   /**\n> >    * \\brief Strip the directory prefix from the path\n> >    * \\param[in] path The path to process\n> > diff --git a/src/libcamera/pipeline/virtual/virtual.cpp b/src/libcamera/pipeline/virtual/virtual.cpp\n> > index efd800ebe3d6..e8ef7e524ccf 100644\n> > --- a/src/libcamera/pipeline/virtual/virtual.cpp\n> > +++ b/src/libcamera/pipeline/virtual/virtual.cpp\n> > @@ -23,6 +23,7 @@\n> >   #include <libcamera/base/flags.h>\n> >   #include <libcamera/base/log.h>\n> > +#include <libcamera/base/utils.h>\n> >   #include <libcamera/control_ids.h>\n> >   #include <libcamera/controls.h>\n> > @@ -57,13 +58,6 @@ uint64_t currentTimestamp()\n> >   } /* namespace */\n> > -template<class... Ts>\n> > -struct overloaded : Ts... {\n> > -\tusing Ts::operator()...;\n> > -};\n> > -template<class... Ts>\n> > -overloaded(Ts...) -> overloaded<Ts...>;\n> > -\n> >   class VirtualCameraConfiguration : public CameraConfiguration\n> >   {\n> >   public:\n> > @@ -428,7 +422,7 @@ bool PipelineHandlerVirtual::initFrameGenerator(Camera *camera)\n> >   {\n> >   \tauto data = cameraData(camera);\n> >   \tauto &frame = data->config_.frame;\n> > -\tstd::visit(overloaded{\n> > +\tstd::visit(utils::overloaded{\n> >   \t\t\t   [&](TestPattern &testPattern) {\n> >   \t\t\t\t   for (auto &streamConfig : data->streamConfigs_) {\n> >   \t\t\t\t\t   if (testPattern == TestPattern::DiagonalLines)\n> >\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 663DDBDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 13 Mar 2026 15:04:37 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A5A07626BE;\n\tFri, 13 Mar 2026 16:04:36 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C56176261B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 13 Mar 2026 16:04:34 +0100 (CET)","from ideasonboard.com (unknown [37.159.122.93])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 48D38F52;\n\tFri, 13 Mar 2026 16:03:25 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"K00ZI599\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1773414205;\n\tbh=NXD3TrbgCUSqQWfuEES5voeuPRpiSfxu0WLfyHBp0PU=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=K00ZI599lnyr6VeTrkjoZJ639w42RpXnG81OX8Mj+zDZcsHi/ZMJK6Z65dwmqlYFL\n\tUX71S8ljqSQQ+Rnva65O1DmsRn1LovDV44c/ycUjmFWh5e5HMQkEZpvJk7175gZ6eB\n\taiVE3alhrq0NUSQvlY3DaroJS/YWi2gsIwVwgP4Q=","Date":"Fri, 13 Mar 2026 16:04:31 +0100","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tDaniel Scally <dan.scally@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH v4 2/7] libcamera: utils: Add overloaded visitor helpers","Message-ID":"<abQlsu39Z9lhNP2-@zed>","References":"<20260313-mali-cru-v4-0-c0d9bc8cd8fa@ideasonboard.com>\n\t<20260313-mali-cru-v4-2-c0d9bc8cd8fa@ideasonboard.com>\n\t<14ba62e2-38a9-43df-89d4-2a27b4c85272@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<14ba62e2-38a9-43df-89d4-2a27b4c85272@ideasonboard.com>","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]