Comments 54
inspired by boost::signals2?
Даже и не знаю, что ответить :) Вообще изначально концепцию слотов в boost как раз позаимствовали из Qt.
Но в таком виде (compile-time соединения), по-моему, boost был первым, или я тут не прав? :)
Соединение все-таки по-моему происходит в runtime. Просто на этапе компиляции теперь можно проверить, осуществимо ли оно.
Насколько я помню, в Qt изначально была идея реализовать механизм сигналов/слотов через шаблоны, как это сделано сейчас в boost. Но от нее отказались, потому что не все компиляторы в то время хорошо поддерживали шаблоны (а для кроссплатформенной библиотеки это критично), и потому что не все, что можно сделать с помощью moc, можно выразить шаблонами.
Подход Qt — более мощный, ценой немного меньшей производительности. А вообще в официальной документации Qt как всегда самое лучшее и полное объяснение: http://qt-project.org/doc/qt-4.8/templates.html
P.S. Я тоже не знаю за что вас минусуют. Вопрос как вопрос.
Насколько я помню, в Qt изначально была идея реализовать механизм сигналов/слотов через шаблоны, как это сделано сейчас в boost. Но от нее отказались, потому что не все компиляторы в то время хорошо поддерживали шаблоны (а для кроссплатформенной библиотеки это критично), и потому что не все, что можно сделать с помощью moc, можно выразить шаблонами.
Подход Qt — более мощный, ценой немного меньшей производительности. А вообще в официальной документации Qt как всегда самое лучшее и полное объяснение: http://qt-project.org/doc/qt-4.8/templates.html
P.S. Я тоже не знаю за что вас минусуют. Вопрос как вопрос.
Вы думаете в бусте этот способ от хорошей жизни? boost::signals даже сравнивать c Qt signals нельзя. boost::signals менее функциональны и очень медленны, судя по тестам доступным в интернетах.
Интересно, за что хоть минусуют? Мне правда интересно, кто первоистичник.
С замыканиями, увы, всё же действует правило в виде недопустимости использования переменных со стека функции, этакая ложка дёгтя так сказать.
В смысле, полноценного использования, как в языках типа шарпа.
Упорно смотрю на код и понимаю, что ничего не понимаю в том, как работают плюсовые замыкания.
Можно понимать их как невидимый класс с перегруженным operator() и конструктором, который делает то, что написано в []. В данном случае
Поэтому тягать с помощью [=] со стека можно что угодно; если нужна мутабельность — копировать указатель и как-то решить вопрос с мусором, как и сделано в примере с помощью new и deleteLater.
struct xxx
{
QDialog* dlg;
xxx(QDialog* _dlg) : dlg(_dlg) {}
operator()(int result)
{
...
}
};
Поэтому тягать с помощью [=] со стека можно что угодно; если нужна мутабельность — копировать указатель и как-то решить вопрос с мусором, как и сделано в примере с помощью new и deleteLater.
Простите, если я чего-то не понимаю, но как заменить такой код в новом синтаксисе?
void SomeClass::Foo(const char *slot) {
...
QAction *action = new QAction(...);
connect(action, SIGNAL(triggered()), this, slot);
...
}
А что насчёт скорости? Есть ли выигрыш/проигрыш, или же старый и новый способы соединения примерно равны по скорости исполнения?
Новый метод будет явно быстрее, так как со строками ему работать не надо. Только вот откуда беспокойство, Вы сигналы сотнями в цикле подключаете?
Сам connect в новом стиле будет немного быстрее (не нужен просмотр таблицы во время выполнения), а в вызове слотов вряд ли что-то изменится.
умоляю дайте пару ссылок на книжки Qt для желающего-но-тупого… из нечестно скачанного… всё сложно =(.
ей богу куплю книгу… очень хочу научится программировать с использованием Qt.
ей богу куплю книгу… очень хочу научится программировать с использованием Qt.
По моему скромному личному мнению, самая лучшая книжка — документация Qt :)
Позвольте провести аналогию.
Лучше Handbook для FreeBSD нет ничего, НО в книге дают не только готовые команды, но и «зачем… почему так… что было до ...». Никогда не пожалел, что в своё время купил книгу.
Образно говоря, документация — это больше справочник.
А хорошая книга — это «ммм, ах вот зачем это делать так» и хорошая книга учит правильным вещам сразу и даёт направление.
Лучше Handbook для FreeBSD нет ничего, НО в книге дают не только готовые команды, но и «зачем… почему так… что было до ...». Никогда не пожалел, что в своё время купил книгу.
Образно говоря, документация — это больше справочник.
А хорошая книга — это «ммм, ах вот зачем это делать так» и хорошая книга учит правильным вещам сразу и даёт направление.
В офоках очень много разжёванных примеров и туториалов. Единственный минус (для многих) — неоконченный и неофициальный перевод на русский. Книги, как мне кажется, нужны уже после прохождения туториалов — для более глубокого понимания.
Аналогия тут неуместна :) Доки и примеры Qt намного лучше чем Handbook.
>… в книге дают не только готовые команды, но и «зачем… почему так… что было до ...»
Образно говоря, документация — это больше справочник.
Понятно: документацию Qt вы в глаза не видели :)
Образно говоря, документация — это больше справочник.
Понятно: документацию Qt вы в глаза не видели :)
Документация и официальные примеры. В книгах вы ничего лучше все равно не найдете.
Когда-то давно, когда я почти не знал английского, но тоже хотел изучить Qt мне помог сайт doc.crossplatform.ru/qt/4.3.2/how-to-learn-qt.html
И в частности doc.crossplatform.ru/qt/4.3.2/tutorial.html
Да, информация слегка устаревшая, но общее представление дает.
После этого можно запускать-читать примеры из Qt Examples и изучать по готовому коду.
И в частности doc.crossplatform.ru/qt/4.3.2/tutorial.html
Да, информация слегка устаревшая, но общее представление дает.
После этого можно запускать-читать примеры из Qt Examples и изучать по готовому коду.
Документацию никто не отменяет, но вот, чтобы начать самое оно:
qt4.ru/blog/books/3.html
qt4.ru/blog/books/3.html
Я, когда-то тоже искал книгу по Qt. В результате что-то нашел, прочитал первые главы и плюнул. Документация тут решает, в отличии от многих других библиотек.
Классика: Бланшет/Саммерфилд. Предпочтительнее читать на английском (если нет серьёзных проблем с языком), там всё очень просто и подробно разжёвано.
Наконец-то. Сколько проблем с connect возникало хотя бы из-за неймспейсов — везде приходилось писать идентификатор одинаково…
Можно ли будет писать так:
Всегда не хватало возможности соединять сигналы-слоты с разными списками аргументов. В примере выше хочется просто вызова без передачи чего-либо.
class Test : public QObject
{ Q_OBJECT
public:
Test() {
connect(this, &Test::someSignal, this, &Test::someSlot);
}
signals:
void someSignal(const QString &);
public:
void someSlot();
};
Всегда не хватало возможности соединять сигналы-слоты с разными списками аргументов. В примере выше хочется просто вызова без передачи чего-либо.
Думаю, что нет. Не вижу способа посчитать количество аргументов переданной функции.
Вообще-то это всегда было возможно :) Смотрите документацию.
Нельзя только чтобы в слоте было меньше аргументов чем в сигнале. Поэтому иногда приходилось использовать QSignalMapper или свои велосипеды. Теперь с C++11 замыкания существенно упростят нам жизнь!
Нельзя только чтобы в слоте было меньше аргументов чем в сигнале. Поэтому иногда приходилось использовать QSignalMapper или свои велосипеды. Теперь с C++11 замыкания существенно упростят нам жизнь!
0 >= 1? Или нулевое количество — исключение?
Так как показано в вашем примере, всегда было можно соединять. Наоборот нельзя, потому что если слот что-то принимает, то ему это, очевидно, надо дать. Ну и соответственно нельзя соединять сигналы и слоты с разными типами параметров, что на мой взгляд очевидно.
Ну, в новом синтаксисе можно будет соединять сигналы и слоты с разными типами параметров, если параметры сигнала имеют возможность неявного приведения к типам параметров слота.
Окей, а как насчет аргументов с дефолтными значениями? Можно ли давать меньше аргументов слоту, в таком случае?
>Всегда не хватало возможности соединять сигналы-слоты с разными списками аргументов.
Уж не знаю, почему вам её «всегда не хватало», но она в Qt всегда была :) Главное, чтобы количество аргументов слота было меньше либо равно количеству аргументов сигнала. Т.е. чтобы не оставалось «висячих» аргументов в слоте.
Избыточная информация — можно, недостаточная — нельзя.
Уж не знаю, почему вам её «всегда не хватало», но она в Qt всегда была :) Главное, чтобы количество аргументов слота было меньше либо равно количеству аргументов сигнала. Т.е. чтобы не оставалось «висячих» аргументов в слоте.
Избыточная информация — можно, недостаточная — нельзя.
Спасибо за статью.
Просто на всякий случай напомню: у метода connect есть еще и пятый аргумент (спасибоНокии Троллтеку за это — он такой клевый!) — Qt::ConnectionType. С его использованием механизм сигналов/слотов играет еще более яркими красками!
Просто на всякий случай напомню: у метода connect есть еще и пятый аргумент (спасибо
На самом деле, не всё с новым синтаксисом сигналов и слотов так хорошо. В статье на Qt-project есть такой вот адский пример:
Комментарий к примеру оттуда же:
Не знаю, насколько проблема актуальна на данный момент, но случай вполне себе из реальной жизни и использование нового синтаксиса превращает код в тотальный треш, угар и содомию. Хорошо, что это хоть чуть-чуть компенсируется возможностью использовать лямбды в качестве слотов.
QTcpSocket *socket = new QTcpSocket;
...
QObject::connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), [socket] (QAbstractSocket::SocketError) {
qDebug()<< "ERROR " << socket->errorString();
socket->deleteLater();
});
Комментарий к примеру оттуда же:
As you might see in the example, connecting to QAbstractSocket::error is not really beautiful since error has an overload, and taking the address of an overloaded function requires explicit casting.
Some macro could help (with c++0x or typeof extensions)
The best thing is probably to recommend not to overload signals or slots …
… but we have been adding overloads in past minor releases of Qt because taking the address of a function was not a use case we support. But now this would be impossible without breaking the source compatibility.
Не знаю, насколько проблема актуальна на данный момент, но случай вполне себе из реальной жизни и использование нового синтаксиса превращает код в тотальный треш, угар и содомию. Хорошо, что это хоть чуть-чуть компенсируется возможностью использовать лямбды в качестве слотов.
Some macro could help
Я только что попробовал, и таки да, при помощи несложных манипуляций с препроцессорными макросами и новыми штуками C++ (я использовал decltype, но должно сработать и с нестандартным typeof) можно делать красиво. Правда, я трогал не Qt5, а просто написал сферический тест в вакууме, но в С++ принципиально возможно вместо
connect(testObject1, &TestClass1::someSignal1, testObject2, &TestClass2::someSlot1);
писать connect(testObject1, someSignal1, testObject2, someSlot1);
с сохранением проверки на этапе компиляции и прочих плюшек.Ну так значимый фрагмент сферического теста в студию! :)
Это заклинание чинит decltype в текущей версии gcc.
А это — кошки, на которых я тренировался:
template<typename T>
struct decltype_t
{
typedef T type;
};
#define DECLTYPE(expr) decltype_t<decltype(expr)>::type
А это — кошки, на которых я тренировался:
template <class T>
void _invoke(T & obj, void (T::*method)())
{
(obj.*method)();
}
#define invoke(obj, method) (_invoke((obj), &DECLTYPE(obj)::method))
class TestClass
{
public:
void someSlot() { cout << "TestClass::someSlot invoked" << endl; }
};
int main()
{
TestClass test;
_invoke(test, &TestClass::someSlot);
invoke(test, someSlot);
return 0;
}
Последний пример приятно напомнил jQuery. Частенько подобного не хватало.
Sign up to leave a comment.
Сигналы и слоты в Qt5