PDA

Просмотр полной версии : ktsignal - библиотека для сигналов


kin4stat
03.09.2021, 19:52
ktsignal​Небольшая библиотека сигналов для C++. Для компиляции потребуется C++17 (на MSVC можно скомпилировать на C++14)

Немного примеров кода​Базовое использование:​Пример ниже показывает базовое использование сигналов

C++:






void
on_click
(
int
value
)
{
}
class
A
{
public
:
void
on_class_click
(
int
value
)
{
}
}
;
int
main
(
)
{
// Сигнал с сигнатурой функции в шаблонном параметре
ktsignal
::
ktsignal

click
{
}
;
// Подключение обычной функции
click
.
connect
(
on_click
)
;
// Подключение member function
A object
;
click
.
connect
(
&
object
,
&
A
::
on_class_click
)
;
// Подключение лямбда функции
click
.
connect
(
[
]
(
int
)
{
}
)
;
// Вызов коллбэков
click
.
emit
(
1
)
;
}




Scoped соединения автоматически отключаются в конце области видимости

C++:






void
on_click
(
int
value
)
{
}
class
A
{
public
:
void
on_class_click
(
int
value
)
{
}
}
;
int
main
(
)
{
ktsignal
::
ktsignal

click
{
}
;
{
auto
connection
=
click
.
scoped_connect
(
on_click
)
;
A object
;
auto
method_connection
=
click
.
scoped_connect
(
&
object
,
&
A
::
on_class_click
)
;
click
.
scoped_connect
(
[
]
(
int
v
)
{
std
::
cout



Подключение / Отключение коллбэков​

C++:





[CODE]
auto
connection
=
click
.
connect
(
on_click
)
;
// Подключение лямбда функции
click
.
connect
(
[
]
(
int
)
{
}
)
;
// Вызов сигнала (on_click и lambda будут вызваны)
click
.
emit
(
1
)
;
// Отключение on_click коллбэка от сигнала
connection
.
disconnect
(
)
;
// Только лямбда будет вызвана
click
.
emit
(
1
)
;




Несколько важных замечаний об объекте

ktsignal_connection




ktsignal_connection

можно создавать по умолчанию, перемещать, но не копировать.

Вы должны убедиться, что соединение не будет использоваться после уничтожения сигнала.
Итерация через слоты сигнала​Вы можете итерироваться по сигналу через range-based for при этом получая значение возврата

C++:






int
on_click
(
int
value
)
{
return
5
;
}
int
on_click_second
(
int
value
)
{
return
1
;
}
int
main
(
)
{
ktsignal
::
ktsignal

click
{
}
;
click
.
connect
(
on_click
)
;
click
.
connect
(
on_click_second
)
;
// Будет выведено `emit_iterate returned 5 emit_iterate returned 1`
for
(
auto
returned
:
signal
.
emit_iterate
(
1
)
)
{
std
::
cout



Также вы легко можете использовать функции из стандартной библиотеки C++

C++:





[CODE]
int
on_click
(
int
value
)
{
return
5
;
}
int
on_click_second
(
int
value
)
{
return
1
;
}
int
main
(
)
{
ktsignal
::
ktsignal

click
{
}
;
click
.
connect
(
on_click
)
;
click
.
connect
(
on_click_second
)
;
auto
iterate
=
signal
.
emit_iterate
(
0
)
;
auto
accumulated
=
std
::
accumulate
(
iterate
.
begin
(
)
,
iterate
.
end
(
)
,
0
)
;
// Will display 6
std
::
cout



Использование ktsignal в многопоточном коде​Для многопоточного кода вы должны использовать
[CODE]
ktsignal_threadsafe


C++:






void
func_thread
(
int
v
)
{
std
::
cout

signal
{
}
;
signal
.
connect
(
func_thread
)
;
// Создание потока который сразу же вызовет emit
std
::
thread
(
[
&
signal
]
(
)
{
// Создание потока который вызовет emit спустя 100мс
std
::
thread
(
[
&
signal
]
(
)
{
std
::
this_thread
::
sleep_for
(
100
ms
)
;
signal
.
emit
(
1
)
;
}
)
.
detach
(
)
;
signal
.
emit
(
2
)
;
}
)
.
join
(
)
;
std
::
this_thread
::
sleep_for
(
1.5
s
)
;
}




Код:






Вывод:
[func_thread] - before sleep
[func_thread] - before sleep
[func_thread] - after sleep
[func_thread] - after sleep




C++:






void
func_thread
(
int
v
)
{
std
::
cout

signal
{
}
;
signal
.
connect
(
func_thread
)
;
// Создание потока который сразу же вызовет emit
std
::
thread
(
[
&
signal
]
(
)
{
// Создание потока который вызовет emit спустя 100мс
std
::
thread
(
[
&
signal
]
(
)
{
std
::
this_thread
::
sleep_for
(
100
ms
)
;
signal
.
emit
(
1
)
;
}
)
.
detach
(
)
;
signal
.
emit
(
2
)
;
}
)
.
join
(
)
;
std
::
this_thread
::
sleep_for
(
1.5
s
)
;
}




Код:






Вывод:
[func_thread] - before sleep
[func_thread] - after sleep
[func_thread] - before sleep
[func_thread] - after sleep




Download & Source:

GitHub - KiN4StAt/ktsignal (https://github.com/KiN4StAt/ktsignal)

Contribute to KiN4StAt/ktsignal development by creating an account on GitHub.

github.com

SR_team
03.09.2021, 21:33
void func_thread(int v) { std::cout signal{}; signal.connect(func_thread); // Создание потока который сразу же вызовет emit std::thread([&signal]() { // Создание потока который вызовет emit спустя 100мс std::thread( [&signal]() { std::this_thread::sleep_for(100ms); signal.emit(1); } ).detach(); signal.emit(2); }).join(); std::this_thread::sleep_for(1.5s); }


как у тебя 1 и 2 в строку разворачивается? Где-то перегрузка опператора = или эти цифры что-то другое означают?

kin4stat
03.09.2021, 21:34
как у тебя 1 и 2 в строку разворачивается? Где-то перегрузка опператора = или эти цифры что-то другое означают?


Как ты лайкнул, я зашел в тему и увидел что проебался в примере.

Исправил до того как ты написал этот ответ.

SR_team
03.09.2021, 21:38
Как ты лайкнул, я зашел в тему и увидел что проебался в примере.
Исправил до того как ты написал этот ответ.


Еще у тебя сигнатура позволяет возвращать что-то из сигналов. Как это работает? emit возвращает список результатов?

UPD: В примере многопоточки сигнал что-то возвращает int(int)

kin4stat
03.09.2021, 21:40
Еще у тебя сигнатура позволяет возвращать что-то из сигналов. Как это работает? emit возвращает список результатов?


emit_iterate позволяет по ним итерироваться(оператор * у итератора делает вызов слота в сигнале).

Не стал делать вектор возвратных значений для emit чтобы не оверхеда. При желании есть emit_iterate который позволяет это сделать

SR_team
03.09.2021, 21:42
оператор * у итератора делает вызов слота в сигнале


Почему не оператор ()? Как это выглядит?

kin4stat
03.09.2021, 22:14
Почему не оператор ()? Как это выглядит?


Оператор * перегружен для вызова функции, чтобы в range-based for можно было красиво получить возвратное значение. Да и в целом это позволяет много красивых вещей делать.

Ну например вот такое:

C++:






auto
iterate
=
signal
.
emit_iterate
(
"test"
)
;
std
::
vector

vec
(
iterate
.
begin
(
)
,
iterate
.
end
(
)
)
;




И в vec будут все значения которые вернулись после вызова коллбэков

(Только что залил обновление на гите, теперь на MSVC можно конструировать STL контейнеры через итераторы. Microsoft решили выебнуться проверкой на поля итератора)



Почему не оператор ()?



Мне кажется что вызов сигнала через () не очень явное действие, поэтому решил сделать на emit. В целом это на сам сигнал никак не влияет



Как это выглядит?


Примерно вот так:

https://forum.antichat.xyz/attachments/27835703/



UPD: В примере многопоточки сигнал что-то возвращает int(int)


UPD: сигнал может что-то возвращать, но при вызове через emit эти значения получить нельзя. Для этих целей стоит юзать emit_iterate и его методы begin и end возвращающие итераторы

vadimka0216
14.09.2021, 15:46
qt на минималках

.deserve
18.09.2021, 11:03
дежавю от документации

kin4stat
18.09.2021, 12:11
дежавю от документации


Делал по принципу буста, доку сам писал, хз

loganhackerdff
14.11.2021, 13:18
https://forum.antichat.xyz/attachments/27887678/

kin4stat
14.11.2021, 14:22
Да ну ты что

https://forum.antichat.xyz/attachments/27887764/

loganhackerdff
14.11.2021, 14:30
Да ну ты что


чо за ***ня тогда, щас перепроверю ещё раз

у меня 0 первый всё равно, щас видос тебе запишу

kin4stat
14.11.2021, 15:31
чо за ***ня тогда, щас перепроверю ещё раз

у меня 0 первый всё равно, щас видос тебе запишу


Подозреваю что там UB, из-за того что ты передаешь rvalue ссылку вместо значения.

Правильная сигнатура должна быть

int(int&&)


но с такой сигнатурой не компилируется код и я не ебу почему, попробую конечно с умами C++ решить проблему, но чет не кажется не выйдет нихуя

loganhackerdff
14.11.2021, 16:07
Подозреваю что там UB, из-за того что ты передаешь rvalue ссылку вместо значения.
Правильная сигнатура должна быть

int(int&&)


но с такой сигнатурой не компилируется код и я не ебу почему, попробую конечно с умами C++ решить проблему, но чет не кажется не выйдет нихуя


я вот свои хотел просто написать, вот что получилосб, они не thread-safe и ещё мне не нравиться проверка std::is_same, я её пытался заменить на std::enabled не не смог пздц