### Macro to Create Executable Targets Source: https://github.com/palacaze/sigslot/blob/master/example/CMakeLists.txt Defines a macro 'pal_create_example' to simplify the creation of executable targets for examples. It adds the executable, links against the Sigslot library, and sets compiler options specific to MSVC. ```cmake macro(pal_create_example target ut) add_executable(${target} EXCLUDE_FROM_ALL "${ut}") target_link_libraries(${target} PRIVATE Pal::Sigslot) target_compile_options(${target} PRIVATE $<$:/bigobj>) target_compile_definitions(${target} PRIVATE $<$:_SCL_SECURE_NO_WARNINGS>) add_dependencies(sigslot-examples ${target}) sigslot_set_properties(${target} PRIVATE) endmacro() ``` -------------------------------- ### Define Custom Target for Examples Source: https://github.com/palacaze/sigslot/blob/master/example/CMakeLists.txt Creates a custom target named 'sigslot-examples' to build all example executables. It's used to group and manage the build process for examples. ```cmake add_custom_target(sigslot-examples COMMENT "Build all the examples.") ``` -------------------------------- ### Install Sigslot using CMake Build Source: https://github.com/palacaze/sigslot/blob/master/readme.md These commands demonstrate how to build and install Sigslot from its root directory using CMake. You can optionally enable SIGSLOT_REDUCE_COMPILE_TIME and specify an installation prefix. ```sh mkdir build && cd build cmake .. -DSIGSLOT_REDUCE_COMPILE_TIME=ON -DCMAKE_INSTALL_PREFIX=~/local cmake --build . --target install # If you want to compile examples: cmake --build . --target sigslot-examples # And compile/execute unit tests: cmake --build . --target sigslot-tests ``` -------------------------------- ### Discover and Process Unit Tests Source: https://github.com/palacaze/sigslot/blob/master/example/CMakeLists.txt This section finds all '.cpp' files recursively from the current source directory and iterates through them to create corresponding build targets. It includes conditional logic for handling Boost and Qt specific examples. ```cmake file(GLOB_RECURSE UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") foreach(ex IN LISTS UNIT_TESTS) string(REPLACE ".cpp" "" target ${ex}) string(REGEX REPLACE "/" "." target ${target}) set(target sigslot-example-${target}) if (target MATCHES "boost") if (TARGET Boost::system) pal_create_example(${target} "${ex}") target_link_libraries(${target} PRIVATE Boost::system) endif() elseif (target MATCHES "qt") if (TARGET Qt5::Core) pal_create_example(${target} "${ex}") target_link_libraries(${target} PRIVATE Qt5::Core) set_target_properties(${target} PROPERTIES AUTOMOC ON) endif() else() pal_create_example(${target} "${ex}") endif() endforeach() ``` -------------------------------- ### Connect Signals Using Freestanding Function Source: https://github.com/palacaze/sigslot/blob/master/readme.md Use the `sigslot::connect()` function to chain signals with compatible arguments. This example connects a signal emitting an int to another emitting a double, and then connects the second signal to a lambda that prints the received double. ```cpp #include #include int main() { sigslot::signal sig1; sigslot::signal sig2; sigslot::connect(sig1, sig2); sigslot::connect(sig2, [] (double d) { std::cout << "got " << d << std::endl; }); sig(1); return 0; } ``` -------------------------------- ### CMake Integration for Sigslot Source: https://context7.com/palacaze/sigslot/llms.txt Integrate Sigslot into your CMake project using `find_package` for installed versions or `FetchContent` for direct repository inclusion. The `Pal::Sigslot` target automatically applies necessary linker flags. ```cmake # Option 1: installed package find_package(PalSigslot REQUIRED) add_executable(MyApp main.cpp) target_link_libraries(MyApp PRIVATE Pal::Sigslot) # Option 2: FetchContent include(FetchContent) FetchContent_Declare( sigslot GIT_REPOSITORY https://github.com/palacaze/sigslot GIT_TAG 19a6f0f5ea11fc121fe67f81fd5e491f2d7a4637 # v1.2.0 ) FetchContent_MakeAvailable(sigslot) target_link_libraries(MyApp PRIVATE Pal::Sigslot) # Option 3: build with reduced compile time (trades performance for smaller code) # cmake .. -DSIGSLOT_REDUCE_COMPILE_TIME=ON -DCMAKE_INSTALL_PREFIX=~/local # cmake --build . --target install ``` -------------------------------- ### Signal with Arguments and Type Conversion Source: https://github.com/palacaze/sigslot/blob/master/readme.md Illustrates creating a signal with specific argument types and connecting slots that accept convertible types or generic arguments. The order of slot invocation is unspecified by default. ```cpp #include #include #include struct foo { // Notice how we accept a double as first argument here. // This is fine because float is convertible to double. // 's' is a reference and can thus be modified. void bar(double d, int i, bool b, std::string &s) { s = b ? std::to_string(i) : std::to_string(d); } }; // Function objects can cope with default arguments and overloading. // It does not work with static and member functions. struct obj { void operator()(float, int, bool, std::string &, int = 0) { std::cout << "I was here\n"; } void operator()() {} }; int main() { // declare a signal with float, int, bool and string& arguments sigslot::signal sig; // a generic lambda that prints its arguments to stdout auto printer = [] (auto a, auto && ...args) { std::cout << a; (void)std::initializer_list{ ((void)(std::cout << " " << args), 1)... }; std::cout << "\n"; }; // connect the slots foo ff; sig.connect(printer); sig.connect(&foo::bar, &ff); sig.connect(obj()); float f = 1.f; short i = 2; // convertible to int std::string s = "0"; // emit a signal sig(f, i, false, s); sig(f, i, true, s); } ``` -------------------------------- ### Process Source Files for Unit Tests Source: https://github.com/palacaze/sigslot/blob/master/test/CMakeLists.txt Iterates through all .cpp files in the source directory, generates test targets using the pal_create_test macro, and conditionally links against Boost or Qt libraries if available. It also enables AUTOMOC for Qt tests. ```cmake file(GLOB_RECURSE UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") foreach(ut IN LISTS UNIT_TESTS) string(REPLACE ".cpp" "" target ${ut}) string(REGEX REPLACE "/" "." target ${target}) set(target sigslot-test-${target}) if (target MATCHES "boost") if (TARGET Boost::system) pal_create_test(${target} "${ut}") target_link_libraries(${target} PRIVATE Boost::system) endif() elseif (target MATCHES "qt") if (TARGET Qt5::Core) pal_create_test(${target} "${ut}") target_link_libraries(${target} PRIVATE Qt5::Core) set_target_properties(${target} PROPERTIES AUTOMOC ON) endif() else() pal_create_test(${target} "${ut}") endif() endforeach() ``` -------------------------------- ### signal::connect() — Connect a slot Source: https://context7.com/palacaze/sigslot/llms.txt Explains how to connect various types of callables (free functions, lambdas, member functions, function objects) to a signal using `connect()`. It also details the return value (`sigslot::connection`), the optional `group_id` for ordering, and the alternative freestanding `sigslot::connect()` function. ```APIDOC ## `signal::connect()` — Connect a slot `connect()` registers a callable as a slot and returns a `sigslot::connection` handle. It accepts free functions, lambdas, function objects, pointers-to-member-functions (with an object pointer), and trackable smart pointers. An optional `group_id` (int32) controls relative invocation order across groups. The freestanding `sigslot::connect(sig, ...)` function provides an equivalent alternative. ```cpp #include #include struct Receiver { void handle(double d) { std::cout << "Receiver got " << d << "\n"; } }; int main() { sigslot::signal sig; Receiver r; // Connect a member function auto c1 = sig.connect(&Receiver::handle, &r); // Connect a lambda with a group id (runs in group 2) auto c2 = sig.connect([](double d){ std::cout << "lambda: " << d << "\n"; }, 2); // Freestanding connect sigslot::connect(sig, [](double d){ std::cout << "free connect: " << d << "\n"; }); sig(3.14); // Output (group 0 before group 2): // Receiver got 3.14 // free connect: 3.14 // lambda: 3.14 std::cout << "slot count: " << sig.slot_count() << "\n"; // 3 } ``` ``` -------------------------------- ### Connect Slots to Signals with Group IDs in C++ Source: https://context7.com/palacaze/sigslot/llms.txt Shows how to connect various callable types to a signal using `connect()` and the freestanding `sigslot::connect()` function. An optional `group_id` can be provided to control the relative invocation order of slots. The `slot_count()` method returns the number of connected slots. ```cpp #include #include struct Receiver { void handle(double d) { std::cout << "Receiver got " << d << "\n"; } }; int main() { sigslot::signal sig; Receiver r; // Connect a member function auto c1 = sig.connect(&Receiver::handle, &r); // Connect a lambda with a group id (runs in group 2) auto c2 = sig.connect([](double d){ std::cout << "lambda: " << d << "\n"; }, 2); // Freestanding connect sigslot::connect(sig, [](double d){ std::cout << "free connect: " << d << "\n"; }); sig(3.14); // Output (group 0 before group 2): // Receiver got 3.14 // free connect: 3.14 // lambda: 3.14 std::cout << "slot count: " << sig.slot_count() << "\n"; // 3 } ``` -------------------------------- ### Basic Signal Connection and Emission Source: https://github.com/palacaze/sigslot/blob/master/readme.md Demonstrates connecting and emitting a parameter-free signal to various callable types including free functions, member functions, static member functions, function objects, and lambdas. Ensure the signal object is declared before connecting slots. ```cpp #include #include void f() { std::cout << "free function\n"; } struct s { void m() { std::cout << "member function\n"; } static void sm() { std::cout << "static member function\n"; } }; struct o { void operator()() { std::cout << "function object\n"; } }; int main() { s d; auto lambda = []() { std::cout << "lambda\n"; }; auto gen_lambda = [](auto && ...a) { std::cout << "generic lambda\n"; }; // declare a signal instance with no arguments sigslot::signal<> sig; // connect slots sig.connect(f); sig.connect(&s::m, &d); sig.connect(&s::sm); sig.connect(o()); sig.connect(lambda); sig.connect(gen_lambda); // a free connect() function is also available sigslot::connect(sig, f); // emit a signal sig(); } ``` -------------------------------- ### Qt Smart Pointer and QObject Lifetime Tracking Source: https://context7.com/palacaze/sigslot/llms.txt Include sigslot/adapter/qt.hpp for QSharedPointer, QWeakPointer, and QObject-derived class lifetime tracking. Connections to QObjects are managed via QPointer, ensuring disconnection when the object is deleted. ```cpp // Qt adapter (requires Qt headers) // #include // #include // // class MyWidget : public QObject { // Q_OBJECT // public: // void onValue(int v) { qDebug() << "value:" << v; } // }; // // sigslot::signal sig; // MyWidget *w = new MyWidget; // sig.connect(&MyWidget::onValue, w); // QObject* tracked via QPointer // sig(42); // delete w; // sig(99); // auto-disconnected ``` -------------------------------- ### Integrate Sigslot with CMake FetchContent Source: https://github.com/palacaze/sigslot/blob/master/readme.md This CMake snippet shows how to integrate Sigslot directly into your project using the FetchContent module. It declares, makes available, and links the Pal::Sigslot target. ```cmake include(FetchContent) FetchContent_Declare( sigslot GIT_REPOSITORY https://github.com/palacaze/sigslot GIT_TAG 19a6f0f5ea11fc121fe67f81fd5e491f2d7a4637 # v1.2.0 ) FetchContent_MakeAvailable(sigslot) add_executable(MyExe main.cpp) target_link_libraries(MyExe PRIVATE Pal::Sigslot) ``` -------------------------------- ### Adapting Functions with Default Arguments Source: https://github.com/palacaze/sigslot/blob/master/readme.md Use a generic bind adapter to connect functions with default arguments to signals when the signal signature does not match the function's full signature. This ensures all arguments are correctly handled during invocation. ```cpp #include #define ADAPT(func) \ [=](auto && ...a) { (func)(std::forward(a)...); } void foo(int &i, int b = 1) { i += b; } int main() { int i = 0; // fine, all the arguments are handled sigslot::signal sig1; sig1.connect(foo); sig1(i, 2); // must wrap in an adapter i = 0; sigslot::signal sig2; sig2.connect(ADAPT(foo)); sig2(i); return 0; } ``` -------------------------------- ### Manage a connection with sigslot::connection Source: https://context7.com/palacaze/sigslot/llms.txt Use `sigslot::connection` to manage signal-slot connections. It provides status queries, temporary blocking, and permanent disconnection. Copying a connection creates another handle to the same underlying slot. ```cpp #include #include int counter = 0; void increment() { ++counter; } int main() { sigslot::signal<> sig; auto conn = sig.connect(increment); sig(); // counter == 1 std::cout << "connected: " << conn.connected() << "\n"; // 1 // Block/unblock conn.block(); sig(); // counter == 1 (blocked) conn.unblock(); sig(); // counter == 2 // RAII block scope { auto blocker = conn.blocker(); // blocks on construction sig(); // counter == 2 (blocked) } // unblocks on destruction sig(); // counter == 3 // Disconnect conn.disconnect(); sig(); // counter == 3 std::cout << "connected: " << conn.connected() << "\n"; // 0 } ``` -------------------------------- ### Boost Smart Pointer Lifetime Tracking Source: https://context7.com/palacaze/sigslot/llms.txt Include sigslot/adapter/boost.hpp to enable lifetime tracking for boost::shared_ptr and boost::weak_ptr. Connections are automatically disconnected when the smart pointer goes out of scope or is reset. ```cpp // Boost adapter #include #include #include #include struct Node { void on_tick(int t) { std::cout << "Node tick " << t << "\n"; } }; int main() { sigslot::signal sig; auto node = boost::make_shared(); sig.connect(&Node::on_tick, node); // tracks boost::shared_ptr lifetime sig(1); // Node tick 1 node.reset(); // destroy the boost shared_ptr sig(2); // silently skipped — auto-disconnected } ``` -------------------------------- ### Declare and Use Typed Signals in C++ Source: https://context7.com/palacaze/sigslot/llms.txt Demonstrates the declaration and usage of thread-safe and single-threaded signals with various slot types including free functions, member functions, static member functions, and lambdas. Ensure the `sigslot/signal.hpp` header is included. ```cpp #include #include #include void on_event() { std::cout << "free function\n"; } struct Handler { void on_data(int val, const std::string &msg) { std::cout << "member: " << val << " " << msg << "\n"; } static void static_cb(int val, const std::string &) { std::cout << "static: " << val << "\n"; } }; int main() { // Zero-argument signal sigslot::signal<> sig0; sig0.connect(on_event); sig0(); // prints "free function" // Typed signal: emits int + string sigslot::signal sig; Handler h; sig.connect(&Handler::on_data, &h); // member function sig.connect(&Handler::static_cb); // static member function sig.connect([](int v, auto) { // lambda std::cout << "lambda: " << v << "\n"; }); sig(42, "hello"); // Output (order unspecified within same group): // member: 42 hello // static: 42 // lambda: 42 // Single-threaded variant (no mutex overhead) sigslot::signal_st fast_sig; fast_sig.connect([](int x){ std::cout << x << "\n"; }); fast_sig(7); // prints 7 } ``` -------------------------------- ### Macro for Creating Test Executables Source: https://github.com/palacaze/sigslot/blob/master/test/CMakeLists.txt A CMake macro to create an executable for a unit test, register it with CTest, and set up dependencies and library linking. It also configures compiler definitions for MSVC. ```cmake macro(pal_create_test target ut) add_executable(${target} EXCLUDE_FROM_ALL "${ut}") add_test(${target} ${target}) add_dependencies(sigslot-tests ${target}) sigslot_set_properties(${target} PRIVATE) target_link_libraries(${target} PRIVATE Pal::Sigslot) target_compile_definitions(${target} PRIVATE $<$:_SCL_SECURE_NO_WARNINGS>) endmacro() ``` -------------------------------- ### Extended Connection Signature for In-Slot Management Source: https://github.com/palacaze/sigslot/blob/master/readme.md Use connect_extended() to provide a slot that accepts a sigslot::connection reference as its first argument. This allows the slot to manage its own connection, such as disconnecting itself after execution. ```cpp #include int main() { int i = 0; sigslot::signal<> sig; // extended connection auto f = [&](auto &con) { i += 1; // do work con.disconnect(); // then disconnects }; sig.connect_extended(f); sig(); // i == 1 sig(); // i == 1 because f was disconnected } ``` -------------------------------- ### Custom Trackable Objects via ADL to_weak() Source: https://context7.com/palacaze/sigslot/llms.txt Enable lifetime tracking for custom types by providing a `to_weak()` overload discoverable via ADL. The returned type must support `expired()`, `lock()`, and `reset()`, similar to `std::weak_ptr`. ```cpp #include #include #include // A custom handle type backed by a shared_ptr struct MyHandle { std::shared_ptr ptr; explicit MyHandle(int v) : ptr(std::make_shared(v)) {} }; // ADL to_weak: must be in the same namespace as MyHandle std::weak_ptr to_weak(const MyHandle &h) { return h.ptr; } int main() { sigslot::signal sig; MyHandle h{1}; sig.connect([](int v){ std::cout << "custom tracked: " << v << "\n"; }, h); sig(10); // custom tracked: 10 h.ptr.reset(); // expire the handle sig(20); // skipped — auto-disconnected std::cout << "slots: " << sig.slot_count() << "\n"; // 0 } ``` -------------------------------- ### Chain Signals Together Source: https://context7.com/palacaze/sigslot/llms.txt Connect signals to other signals using `sigslot::connect(sig1, sig2)` to create event fan-out or pipeline patterns. When `sig1` emits, `sig2` is also triggered. This works with signals having compatible or convertible argument types. ```cpp #include #include int main() { sigslot::signal source; sigslot::signal relay; sigslot::signal sink; // Chain: source -> relay -> sink sigslot::connect(source, relay); sigslot::connect(relay, sink); sink.connect([](int v){ std::cout << "sink received: " << v << "\n"; }); source(42); // propagates through relay to sink // Output: sink received: 42 // Also works with convertible types sigslot::signal wide; sigslot::connect(source, wide); // int is convertible to double wide.connect([](double d){ std::cout << "wide: " << d << "\n"; }); source(7); // Output: // sink received: 7 // wide: 7 } ``` -------------------------------- ### Intrusive Slot Lifetime Tracking with sigslot::observer Source: https://github.com/palacaze/sigslot/blob/master/readme.md Demonstrates intrusive lifetime tracking for slots using sigslot::observer and sigslot::observer_st. The former is thread-safe. Ensure proper disconnection in multithreaded contexts by calling disconnect_all() in the destructor. ```cpp #include int sum = 0; struct s : sigslot::observer_st { void f(int i) { sum += i; } }; struct s_mt : sigslot::observer { ~s_mt() { // Needed to ensure proper disconnection prior to object destruction // in multithreaded contexts. this->disconnect_all(); } void f(int i) { sum += i; } }; int main() { sum = 0; signal sig; { // Lifetime of object instance p is tracked s p; s_mt pm; sig.connect(&s::f, &p); sig.connect(&s_mt::f, &pm); sig(1); // sum == 2 } // The slots got disconnected at instance destruction sig(1); // sum == 2 } ``` -------------------------------- ### Connecting Overloaded Functions with Explicit Casting Source: https://github.com/palacaze/sigslot/blob/master/readme.md Provides a solution for connecting overloaded functions by using an explicit cast with a helper template function to resolve the correct overload. This is necessary because a raw pointer to an overloaded member function does not map to a unique symbol. ```cpp #include template constexpr auto overload(void (C::*ptr)(Args...)) { return ptr; } template constexpr auto overload(void (*ptr)(Args...)) { return ptr; } struct obj { void operator()(int) const {} void operator()() {} }; struct foo { void bar(int) {} void bar() {} static void baz(int) {} static void baz() {} }; void moo(int) {} void moo() {} int main() { sigslot::signal sig; // connect the slots, casting to the right overload if necessary foo ff; sig.connect(overload(&foo::bar), &ff); sig.connect(overload(&foo::baz)); sig.connect(overload(&moo)); sig.connect(obj()); sig(0); return 0; } ``` -------------------------------- ### signal::connect_extended() — Connect a slot with self-managed connection Source: https://context7.com/palacaze/sigslot/llms.txt Describes `connect_extended()`, which allows a slot to receive its `sigslot::connection&` as an argument. This enables slots to disconnect themselves during execution, useful for implementing one-shot slots. ```APIDOC ## `signal::connect_extended()` — Connect a slot with self-managed connection `connect_extended()` passes a `sigslot::connection&` as the first argument to the callable, enabling the slot to inspect or disconnect its own connection during execution. This is useful for one-shot slots that should fire once and then disconnect themselves. ```cpp #include #include int main() { sigslot::signal sig; int call_count = 0; // One-shot slot: disconnects itself after first invocation sig.connect_extended([&](sigslot::connection &con, int val) { std::cout << "fired with " << val << "\n"; ++call_count; con.disconnect(); // self-disconnect }); sig(1); // prints "fired with 1", call_count == 1 sig(2); // slot already disconnected, nothing printed sig(3); // same std::cout << "call_count: " << call_count << "\n"; // 1 std::cout << "slots: " << sig.slot_count() << "\n"; // 0 } ``` ``` -------------------------------- ### Integrate Sigslot with CMake Source: https://github.com/palacaze/sigslot/blob/master/readme.md Use this snippet to link your executable against the Pal::Sigslot target when using Sigslot with CMake. Ensure you have found the PalSigslot package first. ```cmake find_package(PalSigslot) add_executable(MyExe main.cpp) target_link_libraries(MyExe PRIVATE Pal::Sigslot) ``` -------------------------------- ### sigslot::signal — Declare a typed signal Source: https://context7.com/palacaze/sigslot/llms.txt Demonstrates the declaration and basic usage of `sigslot::signal` for zero-argument and typed signals, including connecting free functions, member functions, static member functions, and lambdas. It also shows the single-threaded variant `sigslot::signal_st`. ```APIDOC ## `sigslot::signal` — Declare a typed signal `sigslot::signal` is the primary thread-safe signal type. It is parameterized with the argument types that will be passed to every connected slot on emission. `sigslot::signal_st` is the non-thread-safe single-threaded variant. Both are aliases of the underlying `signal_base` template. ```cpp #include #include #include void on_event() { std::cout << "free function\n"; } struct Handler { void on_data(int val, const std::string &msg) { std::cout << "member: " << val << " " << msg << "\n"; } static void static_cb(int val, const std::string &) { std::cout << "static: " << val << "\n"; } }; int main() { // Zero-argument signal sigslot::signal<> sig0; sig0.connect(on_event); sig0(); // prints "free function" // Typed signal: emits int + string sigslot::signal sig; Handler h; sig.connect(&Handler::on_data, &h); // member function sig.connect(&Handler::static_cb); // static member function sig.connect([](int v, auto) { // lambda std::cout << "lambda: " << v << "\n"; }); sig(42, "hello"); // Output (order unspecified within same group): // member: 42 hello // static: 42 // lambda: 42 // Single-threaded variant (no mutex overhead) sigslot::signal_st fast_sig; fast_sig.connect([](int x){ std::cout << x << "\n"; }); fast_sig(7); // prints 7 } ``` ``` -------------------------------- ### Enforce Slot Invocation Order with Slot Groups Source: https://github.com/palacaze/sigslot/blob/master/readme.md Assign group IDs to slots to control their relative invocation order. Slots within the same group have unspecified order, but groups are invoked in ascending ID order. Unassigned slots default to group 0. ```cpp #include #include #include int main() { sigslot::signal<> sig; // simply assigning a group id as last argument to connect sig.connect([] { std::puts("Second"); }, 1); sig.connect([] { std::puts("Last"); }, std::numeric_limits::max()); sig.connect([] { std::puts("First"); }, -10); sig(); return 0; } ``` -------------------------------- ### sigslot::connection Source: https://context7.com/palacaze/sigslot/llms.txt The `connection` object provides a non-owning handle to a slot, allowing for status checks, temporary blocking, and permanent disconnection. Copying a `connection` creates another handle to the same slot. ```APIDOC ## `sigslot::connection` — Manage a connection `connection` is a lightweight non-owning handle (backed by a `std::weak_ptr`) to a slot. It provides status queries (`valid()`, `connected()`), temporary blocking (`block()` / `unblock()`), RAII block scope via `blocker()`, and permanent disconnection (`disconnect()`). Copying a `connection` produces another handle to the same underlying slot. ```cpp #include #include int counter = 0; void increment() { ++counter; } int main() { sigslot::signal<> sig; auto conn = sig.connect(increment); sig(); // counter == 1 std::cout << "connected: " << conn.connected() << "\n"; // 1 // Block/unblock conn.block(); sig(); // counter == 1 (blocked) conn.unblock(); sig(); // counter == 2 // RAII block scope { auto blocker = conn.blocker(); // blocks on construction sig(); // counter == 2 (blocked) } // unblocks on destruction sig(); // counter == 3 // Disconnect conn.disconnect(); sig(); // counter == 3 std::cout << "connected: " << conn.connected() << "\n"; // 0 } ``` ``` -------------------------------- ### Automatic Slot Lifetime Tracking Source: https://github.com/palacaze/sigslot/blob/master/readme.md Sigslot can automatically disconnect slots when their lifetime ends by tracking objects convertible to weak pointers. This includes std::shared_ptr, std::weak_ptr, and adapters for boost and Qt smart pointers, as well as QObjects. ```cpp #include #include int sum = 0; struct s { void f(int i) { sum += i; } }; class MyObject : public QObject { Q_OBJECT public: void add(int i) const { sum += i; } }; int main() { sum = 0; signal sig; // track lifetime of object and also connect to a member function auto p = std::make_shared(); sig.connect(&s::f, p); sig(1); // sum == 1 p.reset(); sig(1); // sum == 1 // track an unrelated object lifetime struct dummy; auto l = [&](int i) { sum += i; }; auto d = std::make_shared(); sig.connect(l, d); sig(1); // sum == 2 d.reset(); sig(1); // sum == 2 // track a QObject { MyObject o; sig.connect(&MyObject::add, &o); sig(1); // sum == 3 } sig(1); // sum == 3 } ``` -------------------------------- ### Managing Signal-Slot Connections Source: https://github.com/palacaze/sigslot/blob/master/readme.md The sigslot::connection object returned by signal::connect() allows for status querying, connection blocking/unblocking, and explicit disconnection. It is not a RAII object but can be converted to sigslot::scoped_connection for automatic scope-based disconnection. ```cpp #include #include int i = 0; void f() { i += 1; } int main() { sigslot::signal<> sig; // keep a sigslot::connection object auto c1 = sig.connect(f); // disconnection sig(); // i == 1 c1.disconnect(); sig(); // i == 1 // scope based disconnection { sigslot::scoped_connection sc = sig.connect(f); sig(); // i == 2 } sig(); // i == 2; // connection blocking auto c2 = sig.connect(f); sig(); // i == 3 c2.block(); sig(); // i == 3 c2.unblock(); sig(); // i == 4 } ``` -------------------------------- ### C++ Structs for Function Pointer Comparison Source: https://github.com/palacaze/sigslot/blob/master/readme.md Defines various C++ structs and their members to demonstrate function pointer behavior and size differences across compilers. This is used to illustrate the complexities of comparing function pointers. ```cpp void fun() {} struct b1 { virtual ~b1() = default; static void sm() {} void m() {} virtual void vm() {} }; struct b2 { virtual ~b2() = default; static void sm() {} void m() {} virtual void vm() {} }; struct c { virtual ~c() = default; virtual void w() {} }; struct d : b1 { static void sm() {} void m() {} void vm() override {} }; struct e : b1, c { static void sm() {} void m() {} void vm() override{} }; ``` -------------------------------- ### Define Sigslot Test Target Source: https://github.com/palacaze/sigslot/blob/master/test/CMakeLists.txt Defines a custom CMake target for building and running all unit tests. It uses ctest to output results on failure. ```cmake add_custom_target(sigslot-tests COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure COMMENT "Build and run all the unit tests.") ``` -------------------------------- ### signal::disconnect() overloads Source: https://context7.com/palacaze/sigslot/llms.txt Provides multiple overloads for disconnecting slots without needing a `connection` handle. Slots can be disconnected by callable, object pointer, or `group_id`. `disconnect_all()` removes all connected slots. ```APIDOC ## `signal::disconnect()` — Disconnect slots without a connection handle `disconnect()` provides four overloads to remove slots without needing to store the original `connection` object: (1) by callable (free/static functions always work; RTTI required for PMFs, function objects, and lambdas); (2) by object pointer or trackable; (3) by both callable and object to pinpoint a specific slot; (4) by `group_id` to clear an entire group. `disconnect_all()` removes every slot. ```cpp #include #include static int n = 0; void f1() { ++n; } void f2() { ++n; } struct S { void m1() { ++n; } void m2() { ++n; } }; int main() { sigslot::signal<> sig; S s1; auto s2 = std::make_shared(); auto lbd = [&]{ ++n; }; sig.connect(f1); // slot A sig.connect(f2); // slot B sig.connect(&S::m1, &s1); // slot C sig.connect(&S::m2, &s1); // slot D sig.connect(&S::m1, s2); // slot E (tracked) sig.connect(lbd); // slot F sig(); // n == 6 sig.disconnect(f2); // removes B sig.disconnect(&S::m1); // removes C and E (all m1 slots) sig.disconnect(lbd); // removes F sig.disconnect(&S::m2, &s1); // removes only D (specific object) sig.disconnect(s2); // s2 already disconnected, no-op sig(); // n == 7 (only A remains) sig.disconnect_all(); sig(); // n == 7 std::cout << "n=" << n << " slots=" << sig.slot_count() << "\n"; // n=7 slots=0 } ``` ``` -------------------------------- ### Block and Unblock Signal Emissions Source: https://context7.com/palacaze/sigslot/llms.txt Use `signal::block()` and `signal::unblock()` to temporarily suppress all slot invocations for a signal without disconnecting any slots. The blocked state is atomic and thread-safe. ```cpp #include #include int main() { sigslot::signal sig; sig.connect([](int v){ std::cout << "got " << v << "\n"; }); sig(1); // prints "got 1" sig.block(); std::cout << "blocked: " << sig.blocked() << "\n"; // 1 sig(2); // suppressed — nothing printed sig(3); // suppressed sig.unblock(); sig(4); // prints "got 4" } ``` -------------------------------- ### Automatic Lifetime Tracking with `std::shared_ptr` Source: https://context7.com/palacaze/sigslot/llms.txt Connect slots using `std::shared_ptr` or `std::weak_ptr` to automatically disconnect the slot when the tracked object is destroyed. This prevents dangling pointer issues without manual management. ```cpp #include #include struct Worker { void process(int val) { std::cout << "Worker::process(" << val << ")\n"; } }; int main() { sigslot::signal sig; auto worker = std::make_shared(); // Track lifetime: slot auto-disconnects when worker is destroyed sig.connect(&Worker::process, worker); sig(1); // Worker::process(1) worker.reset(); // destroy the shared_ptr sig(2); // silently skipped — slot auto-disconnected std::cout << "slots: " << sig.slot_count() << "\n"; // 0 // Track an unrelated object alongside a lambda auto guard = std::make_shared(1); sig.connect([](int v){ std::cout << "lambda: " << v << "\n"; }, guard); sig(3); // lambda: 3 guard.reset(); sig(4); // skipped } ``` -------------------------------- ### Disconnection without Connection Object in Sigslot Source: https://github.com/palacaze/sigslot/blob/master/readme.md Illustrates various methods for disconnecting slots without needing a connection object. Supports disconnection by callable, object pointer, or group ID. RTTI may be required for certain types of member function pointers. ```cpp #include #include static int i = 0; void f1() { i += 1; } void f2() { i += 1; } struct s { void m1() { i += 1; } void m2() { i += 1; } void m3() { i += 1; } }; struct o { void operator()() { i += 1; } }; int main() { sigslot::signal<> sig; s s1; auto s2 = std::make_shared(); auto lbd = [&] { i += 1; }; sig.connect(f1); // #1 sig.connect(f2); // #2 sig.connect(&s::m1, &s1); // #3 sig.connect(&s::m2, &s1); // #4 sig.connect(&s::m3, &s1); // #5 sig.connect(&s::m1, s2); // #6 sig.connect(&s::m2, s2); // #7 sig.connect(o{}); // #8 sig.connect(lbd); // #9 sig(); // i == 9 sig.disconnect(f2); // #2 is removed sig.disconnect(&s::m1); // #3 and #6 are removed sig.disconnect(o{}); // #8 and is removed // sig.disconnect(&o::operator()); // same as the above, more efficient sig.disconnect(lbd); // #9 and is removed sig.disconnect(s2); // #7 is removed sig.disconnect(&s::m3, &s1); // #5 is removed, not #4 sig(); // i == 11 sig.disconnect_all(); // remove all remaining slots return 0; } ``` -------------------------------- ### Self-Disconnecting Slots with `connect_extended` in C++ Source: https://context7.com/palacaze/sigslot/llms.txt Utilizes `connect_extended()` to connect a slot that receives its own `sigslot::connection` object. This allows the slot to disconnect itself during execution, useful for one-shot callbacks. The `slot_count()` method reflects the number of active slots. ```cpp #include #include int main() { sigslot::signal sig; int call_count = 0; // One-shot slot: disconnects itself after first invocation sig.connect_extended([&](sigslot::connection &con, int val) { std::cout << "fired with " << val << "\n"; ++call_count; con.disconnect(); // self-disconnect }); sig(1); // prints "fired with 1", call_count == 1 sig(2); // slot already disconnected, nothing printed sig(3); // same std::cout << "call_count: " << call_count << "\n"; // 1 std::cout << "slots: " << sig.slot_count() << "\n"; // 0 } ``` -------------------------------- ### Enforce Slot Invocation Order with Groups Source: https://context7.com/palacaze/sigslot/llms.txt Assign `sigslot::group_id` to slots to control their invocation order. Groups are processed in ascending numerical order. The default group is 0. Any `int32_t` value is valid for group IDs. ```cpp #include #include #include int main() { sigslot::signal sig; sig.connect([](auto s){ std::cout << "3. third (" << s << ")\n"; }, 2); sig.connect([](auto s){ std::cout << "4. last (" << s << ")\n"; }, std::numeric_limits::max()); sig.connect([](auto s){ std::cout << "1. first (" << s << ")\n"; }, -100); sig.connect([](auto s){ std::cout << "2. second (" << s << ")\n"; }, 0); sig("event"); // Output (guaranteed order): // 1. first (event) // 2. second (event) // 3. third (event) // 4. last (event) // Disconnect an entire group sig.disconnect(2); sig("again"); // Output: // 1. first (again) // 2. second (again) // 4. last (again) } ``` -------------------------------- ### RAII connection lifetime with sigslot::scoped_connection Source: https://context7.com/palacaze/sigslot/llms.txt Utilize `sigslot::scoped_connection` for automatic disconnection when the connection object goes out of scope. It is implicitly constructible from a `connection` or the return value of `connect()`, and it is move-only. ```cpp #include #include int val = 0; void add(int x) { val += x; } int main() { sigslot::signal sig; { // scoped_connection disconnects when it leaves this block sigslot::scoped_connection sc = sig.connect(add); sig(10); // val == 10 sig(5); // val == 15 } // sc destroyed -> slot disconnected sig(100); // no slot connected, val stays 15 std::cout << "val: " << val << "\n"; // 15 std::cout << "slots: " << sig.slot_count() << "\n"; // 0 // connect_scoped() as an alternative auto sc2 = sig.connect_scoped(add); sig(1); } // sc2 goes out of scope -> disconnected ```