Commit Graph

5 Commits

Author SHA1 Message Date
Laurent Pinchart
48d7bb29bd libcamera: base: signal: Disable connect() for functor if args mismatch
If a pointer-to-member is passed to the Signal::connect() function with
arguments that don't match the Signal type, the pointer-to-member
version of connect() will not match during template argument resolution,
but the functor version will. This results in a compilation error in the
BoundMethodFunctor class, due to the pointer-to-member not being a
functor and thus not being callable directly. The error messages are
quite cryptic. With the following error applied,

diff --git a/test/signal.cpp b/test/signal.cpp
index 5c6b304dac0b..6dd11ac45313 100644
--- a/test/signal.cpp
+++ b/test/signal.cpp
@@ -107,6 +107,7 @@ protected:
 		/* Test signal emission and reception. */
 		called_ = false;
 		signalVoid_.connect(this, &SignalTest::slotVoid);
+		signalVoid_.connect(this, &SignalTest::slotInteger1);
 		signalVoid_.emit();

 		if (!called_) {

gcc outputs

../../include/libcamera/base/bound_method.h: In instantiation of ‘R libcamera::BoundMethodFunctor<T, R, Func, Args>::activate(Args ..., bool) [with T = SignalTest; R = void; Func = void (SignalTest::*)(int); Args = {}]’:
../../include/libcamera/base/bound_method.h:143:4:   required from here
../../include/libcamera/base/bound_method.h:146:37: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((libcamera::BoundMethodFunctor<SignalTest, void, void (SignalTest::*)(int)>*)this)->libcamera::BoundMethodFunctor<SignalTest, void, void (SignalTest::*)(int)>::func_ (...)’, e.g. ‘(... ->* ((libcamera::BoundMethodFunctor<SignalTest, void, void (SignalTes
t::*)(int)>*)this)->libcamera::BoundMethodFunctor<SignalTest, void, void (SignalTest::*)(int)>::func_) (...)’
  146 |                         return func_(args...);
      |                                ~~~~~^~~~~~~~~

and clang isn't much better:

../../include/libcamera/base/bound_method.h:146:11: error: called object type 'void (SignalTest::*)(int)' is not a function or function pointer
                        return func_(args...);
                               ^~~~~
../../include/libcamera/base/bound_method.h:137:2: note: in instantiation of member function 'libcamera::BoundMethodFunctor<SignalTest, void, void (SignalTest::*)(int)>::activate' requested here
        BoundMethodFunctor(T *obj, Object *object, Func func,
        ^
../../include/libcamera/base/signal.h:80:27: note: in instantiation of member function 'libcamera::BoundMethodFunctor<SignalTest, void, void (SignalTest::*)(int)>::BoundMethodFunctor' requested here
                SignalBase::connect(new BoundMethodFunctor<T, void, Func, Args...>(obj, nullptr, func));
                                        ^
../../test/signal.cpp:110:15: note: in instantiation of function template specialization 'libcamera::Signal<>::connect<SignalTest, void (SignalTest::*)(int), nullptr>' requested here
                signalVoid_.connect(this, &SignalTest::slotInteger1);
                            ^

Improve error reporting by disabling the functor version of connect()
when the Func argument isn't invocable with the Signal arguments. gcc
will then complain with

../../test/signal.cpp:110:36: error: no matching function for call to ‘libcamera::Signal<>::connect(SignalTest*, void (SignalTest::*)(int))’
  110 |                 signalVoid_.connect(this, &SignalTest::slotInteger1);
      |                 ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and clang with

../../test/signal.cpp:110:15: error: no matching member function for call to 'connect'
                signalVoid_.connect(this, &SignalTest::slotInteger1);
                ~~~~~~~~~~~~^~~~~~~

which are more readable.

This change requires usage of std::is_invocable<>, which is only
available starting in C++17. This is fine for usage of the Signal class
within libcamera, as the project is compiled with C++17, but we try to
keep the public API compatible C++14. Condition the additional checks
based on the C++ version.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2022-08-31 13:58:00 +03:00
Laurent Pinchart
1715b7ed08 libcamera: Drop unnecessary typename keyword used with std::enable_if_t
Usage of the std::enable_if_t type doesn't need to be prefixed by
typename. Drop the unnecessary keyword.

Reported-by: Jacopo Mondi <jacopo@jmondi.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
2022-07-28 18:47:17 +03:00
Kieran Bingham
0701f756b9 libcamera: base: Convert to pragma once
Remove the verbose #ifndef/#define/#endif pattern for maintaining
header idempotency, and replace it with a simple #pragma once.

This simplifies the headers, and prevents redundant changes when
header files get moved.

Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
2021-11-24 12:18:11 +00:00
Laurent Pinchart
58720e1dc9 libcamera: base: signal: Support connecting signals to functors
It can be useful to connect a signal to a functor, and in particular a
lambda function, while still operating in the context of a receiver
object (to support both object-based disconnection and queued
connections to Object instances).

Add a BoundMethodFunctor class to bind a functor, and a corresponding
Signal::connect() function. There is no corresponding disconnect()
function, as a lambda passed to connect() can't be later passed to
disconnect(). Disconnection typically uses disconnect(T *object), which
will cover the vast majority of use cases.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
2021-09-02 01:16:45 +03:00
Kieran Bingham
27aff949fb libcamera/base: Move extended base functionality
Move the functionality for the following components to the new
base support library:

 - BoundMethod
 - EventDispatcher
 - EventDispatcherPoll
 - Log
 - Message
 - Object
 - Signal
 - Semaphore
 - Thread
 - Timer

While it would be preferable to see these split to move one component
per commit, these components are all interdependent upon each other,
which leaves us with one big change performing the move for all of them.

Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2021-06-25 16:11:08 +01:00