Russian Qt Forum
Май 10, 2024, 07:46 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4 ... 8   Вниз
  Печать  
Автор Тема: Частный случай механизма сигнал-слот  (Прочитано 72045 раз)
brankovic
Гость
« Ответ #15 : Февраль 18, 2011, 23:26 »

И реализация в Qt это не единственная её реализация. Я не хочу сказать, что в Qt с помощью moc - это круто, напротив, вызов обходится дороже, чем например в схеме сигнал-слот в boost.

У схемы qt есть и преимущества, но в контексте программирования их бессмысленно обсуждать. Потому что схема qt не програмисстская -- это бизнес-схема. Во времена создания qt не было _ни одного_ компилятора, который поддерживал бы шаблоны в полном объёме, и глючили они все по-разному. Кросс-платформенная библиотека основанная на шаблонах была бы обречена. Оставались макросы. Тролли решили, что moc выделит их из серой толпы макросовых фреймворков, и были по-своему правы.

Во-вторых я предложил вариант сигнал-слот отличный от реализованного в Qt и отличный от реализации в boost::signal.

чем ближе ваша реализация подойдёт к функционалу boost::signal, тем более похожей на него она станет. Потом они сольются и станет всё равно, что использовать. И тогда, возможно, вы станете использовать boost::signal.

Да и что "такого уж хорошего" в ихней схеме слот/сигнал? Везде есть нормальное "sendEvent" (выполнить немедленно) и "postEvent" (засунуть в очередь).

получается функция-обработчик событий на 2-3 тысячи строк, причём править её надо при добавлении любого события, инкапсуляции никакой (все события проходят один луп), как результат тоже путаница, только другого толка.

И я считаю имеет право быть, хотя бы как объект теоретического исследования)
Короче,
Нет ничего практичнее хорошей теории))

Жил некогда Чжу, который учился убивать драконов.. Улыбающийся

Но упражнение в любом случае полезное.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #16 : Февраль 19, 2011, 20:13 »

Дописал)

Теперь соединение автоматически разрывается, если один из объектов уничтожается.
Пришлось для этого писать свой умный указатель (smart_ptr), который следит за всем этим делом..
Зато получаем все плюшки автоматического удаления объектов  Смеющийся

Все классы помещены в пространство имён ssc (от signal slot connection)
Базовые два класса это:
1) signal
2) smart_ptr

Используется так:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
class A
{
public:
   A() {
       std::cout << "A()" << std::endl;
   }
   ~A() {
       std::cout << "~A()" << std::endl;
   }
   ssc::signal<void, std::string> my_signal;
 
   void run() {
       my_signal("Hello Word!");
   }
};
 
class B
{
public:
   B() : _i(0) {
       std::cout << "B()" << std::endl;
   }
   B(int i) : _i(i) {
       std::cout << "B(int  i = " << _i << ")" << std::endl;
   }
   ~B() {
       std::cout << "~B();  i = " << _i << std::endl;
   }
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << "  i = " << _i << std::endl;
   }
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << "  i = " << _i << std::endl;
   }
private:
   int _i;
};
 
int main()
{
   ssc::smart_ptr<A> a = new A;
   // A *a = new A;        можно и так, но придётся удалять руками
 
   //{  если раскомментировать, соединения автоматически разорвуться
 
       ssc::smart_ptr<B> p(new B(12));
   /*  B *b = new B(12)       а вот так можно, но в connect мы его не сможем засунуть
        поскольку connect хочет чтоб b был умным))    
   */

       connect(a->my_signal, p, &B::slot1);
       connect(a->my_signal, p, &B::slot2);
 
   //} см. выше
 
   a->run();
 
   return 0;
}
 


Исходники прилогаются. Прошу потестить, кому не лень. Возможно я где нить накасячил)
Конструктивная критика приветствуется)

 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
brankovic
Гость
« Ответ #17 : Февраль 20, 2011, 00:13 »

1) signal
2) smart_ptr

smart_ptr просто ужасный:

1. деструктор и operator= должны вызывать общий метод destroy, чтобы их поведение было консистентным (в operator= вы забыли *valid=0, кроме того is_killer обнуляется и объект никто не удалит -- утечка памяти)

2. smart_ptr это симметричный объект, не может быть один "киллер", потому что если он погибнет раньше остальных, у других ptr-а не станет. Каждый владелец ptr может оказаться последним, "киллером".
Записан
brankovic
Гость
« Ответ #18 : Февраль 20, 2011, 00:22 »

1) signal
2) smart_ptr

По сигналу: теперь ресивера _обязательно_ заворачивать в smart_ptr?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #19 : Февраль 20, 2011, 01:06 »

1) signal
2) smart_ptr

По сигналу: теперь ресивера _обязательно_ заворачивать в smart_ptr?
Теперь обязательно, для того что бы при уничтожении receiver а разрывалось и соответствующее соединение.
Хотя есть и другой вариант как это сделать без использования smart_ptr.

1) signal
2) smart_ptr

smart_ptr просто ужасный:

1. деструктор и operator= должны вызывать общий метод destroy, чтобы их поведение было консистентным (в operator= вы забыли *valid=0, кроме того is_killer обнуляется и объект никто не удалит -- утечка памяти)
Постараюсь объяснить логику этого указателя (для краткости в дальнейшем просто ptr):
ptr может быть либо киллером либо нет. У киллера есть право убить объект. Т.е. право убить объект принадлежит тому, кто первый им завладел. пример:
Код
C++ (Qt)
smart_ptr<B> p1(new B); // p1 - киллер и убъёт объект
smart_ptr<B> p2 = p1;
/* p2 - не имееет права убивать объект, он просто копирует указатель на
на него. флаг _is_killer = false. Сам объект не клонируется.  */

 
Другая ситуация:
Код
C++ (Qt)
smart_ptr<B> p1(new B); // p1 - киллер и убъёт объект
smart_ptr<B> p2(new B); // p2 - тоже киллер!
// Внимание фокус!
p2 = p1; /* Поскольку p2 - киллер он вначале убъёт объект на который ссылается,
затем скопирует указатель на объект на который ссылается p1.
Далее он сбросит флаг _is_killer = false и лишится права удалять объект,
поскольку им уже владел до него p1 и владеет.
Флаг _valid он скопирует также, и соответственно _valid == true, так что пока всё хорошо))  */

// А вот здесь:
 
p1 = p2; /* Ничего не произойдёт, поскольку  operatop=() сначало проверяет не ссылаются
ли они на один и тот же объект. И если да (а в данном случае так и есть)
то return *this и всё.*/

 

Т.е. идея в том, что указателей на объект может быть много, но среди них только у одного есть право его убить. Каждый указатель может изменять данные объекта, но не клонировать его при этом. После того, как киллер  убъёт объект, все остальные смогут узнать об этом, за счёт флага _valid, который будет равен *_valid == false.
Кстати, вот он так и будет висеть и никто его никогда не удалит, но это 1 висячий байт... За то польза))

Цитировать
2. smart_ptr это симметричный объект, не может быть один "киллер", потому что если он погибнет раньше остальных, у других ptr-а не станет. Каждый владелец ptr может оказаться последним, "киллером".

Если киллер умрёт, то он за одно убъёт и сам объект и зделает не валидными оставшиеся ptrЫ. Я такого поведения от него и добивался.

А как Вы видете это всё? Как по Вашему более правильно организовать логику?
Спасибо за обсуждение)  
« Последнее редактирование: Февраль 20, 2011, 01:25 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
brankovic
Гость
« Ответ #20 : Февраль 20, 2011, 09:53 »

А как Вы видете это всё? Как по Вашему более правильно организовать логику?

Чем не нравится такой ptr:

1. утечка памяти (не удаляется valid)
2. туманная семантика (хотя тут я, возможно, просто мыслю шаблонами типа "должно быть как boost::shared_ptr")
3. не тред-сейф (легко исправить)

Почему бы не выкинуть is_killer и вместо bool is_valid не сделать int counter? Завладев указателем счётчик увеличиваем, потеряв его (через деструктор или operator=) счётчик уменьшаем. Последний владелец это тот, кто опустит счётчик до нуля, тогда можно удалить и счётчик и T.

Теперь обязательно, для того что бы при уничтожении receiver а разрывалось и соответствующее соединение.
Хотя есть и другой вариант как это сделать без использования smart_ptr.

как раз хочется другой вариант. smart_ptr всё равно понадобится, но чтобы спрятать его внутрь
Записан
brankovic
Гость
« Ответ #21 : Февраль 20, 2011, 10:26 »

Код:
smart_ptr<B> p1(new B); // p1 - киллер и убъёт объект
smart_ptr<B> p2(new B); // p2 - тоже киллер!
// Внимание фокус!
p2 = p1; /* Поскольку p2 - киллер он вначале убъёт объект на который ссылается,

operator= должен установить is_valid для p2 в ноль
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #22 : Февраль 20, 2011, 12:30 »

Цитировать
Чем не нравится такой ptr:

1. утечка памяти (не удаляется valid)
2. туманная семантика (хотя тут я, возможно, просто мыслю шаблонами типа "должно быть как boost::shared_ptr")
3. не тред-сейф (легко исправить)

Почему бы не выкинуть is_killer и вместо bool is_valid не сделать int counter? Завладев указателем счётчик увеличиваем, потеряв его (через деструктор или operator=) счётчик уменьшаем. Последний владелец это тот, кто опустит счётчик до нуля, тогда можно удалить и счётчик и T.
Да, Вы правы, я малость перемудрил с ptr. Вариант с каунтером гораздо лучше.
У меня просто в голове крутилась идея что убить объект должен именно тот, кто им первым завладеет..

Цитировать
как раз хочется другой вариант. smart_ptr всё равно понадобится, но чтобы спрятать его внутрь
 
Другой вариант заклюсается в том, что мы создаём в класса receivera некий объект шпион, который будет следить за своим хозяином:
Код
C++ (Qt)
class B
{
public:
   B() {}
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << std::endl;
   }
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << std::endl;
   }
 
   ssc::spy spy;     // Вот этот объект. Его предназначение, следить за своим владельцем.
 
private:
   int _i;
};
 
Но теперь, при создании соединения необходимо также передать ссылку на шпиона (млин, теперь в connect на один аргумент стало больше  Злой ) пример:
Код
C++ (Qt)
int main()
{
   A *a = new A;
   B *b = new B(12);
 
   connect(a->my_signal, b, &B::slot1, b->spy);
   connect(a->my_signal, b, &B::slot2, b->spy);
 
   a->run();
 
   return 0;
}
 

Всё.. Если теперь удалить объект delete b то соединение разорвётся.

Сам шпион представляет из себя следующее:
Код
C++ (Qt)
class spy
{
public:
   spy() : _valid(new bool(true)) {}
   ~spy() { *_valid = false; }
   bool operator()() const { return *_valid; }
   template <class T1, class T2, class T3> friend class manager_connection;
private:
   bool *_valid;
};
 

Хотя на первый взгляд, при уничтожении spy происходит утечка (остаётся висячим _valid) это не совсем так, поскольку его другом является manager_connection и соответственно имеет доступ к его закрытым членам и он ответственен за зачистку указателя _valid.
Теперь, при уничтожении хозяина: delete b, будет также вызван деструктор шпиона, который сделает: *_valid = false;
Но соединение с объектом b создано раньше и владеет указателем на _valid и поэтому всегда знает, что в данный момент происходит с b.
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
BRE
Гость
« Ответ #23 : Февраль 20, 2011, 12:49 »

Следующий шаг - это наследование класса recivera от класса spy, вместо создания его экземпляра и можно переименовывать spy в trackble.  Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Февраль 20, 2011, 13:20 »

А если делать это по простому/народному, не связываясь ни с какими указателями? Ну у объекта 2 контейнера указателей - кому он посылает и кто ему посылает. Деструкторы вычеркивают из этих контейнеров, оператор = может копировать контейнеры, а может и нет (как нравится). Ну "навести песики" типа
Код
C++ (Qt)
class CMyClass : public CSignalReceiver, public CSignalSender {..
 

Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #25 : Февраль 20, 2011, 13:50 »

Следующий шаг - это наследование класса recivera от класса spy, вместо создания его экземпляра и можно переименовывать spy в trackble.  Улыбающийся
Подмигивающий Но всё же эти две реализации схемы сигнал-слот отличаются)
Идея отнаследоваться от spy это хорошо, мы теперь уже явно в коннект не будем передавать шпиона.. 

А если делать это по простому/народному, не связываясь ни с какими указателями? Ну у объекта 2 контейнера указателей - кому он посылает и кто ему посылает. Деструкторы вычеркивают из этих контейнеров, оператор = может копировать контейнеры, а может и нет (как нравится). Ну "навести песики" типа
Код
C++ (Qt)
class CMyClass : public CSignalReceiver, public CSignalSender {..
 

А что если я хочу посылать сигналы объектам разных классов и принимать сигналы от объектов разных классов? И не думать о том каким именно объектам мне слать и получать до того момента когда наступет нужда создать соединение (уже в самом пользовательском коде)? 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #26 : Февраль 20, 2011, 15:00 »

Переписал smart_ptr, как предложил brankovic
Вроде сейчас утечек нет:
Код
C++ (Qt)
#ifndef SMART_PTR_H
#define SMART_PTR_H
 
namespace ssc {
 
template <class T>
class smart_ptr
{
public:
   smart_ptr();
   smart_ptr(const smart_ptr<T> &other);
   smart_ptr(T *p);
   ~smart_ptr();
 
   bool is_null() const;
   T* operator->() const;
   T& operator*() const;
   T* get() const;
 
   smart_ptr<T> &operator=(const smart_ptr<T> &p);
 
private:
   T *_obj;
   int *_counter;
 
   void try_destroy();
   smart_ptr<T> &operator=(T*);
};
 
template <class T>
inline smart_ptr<T>::smart_ptr()
   : _obj(0), _counter(0)
{
}
 
template <class T>
inline smart_ptr<T>::smart_ptr(const smart_ptr<T> &other)
   : _obj(other._obj), _counter(other._counter)
{
   if (_counter)
       (*_counter)++;
}
 
template <class T>
inline smart_ptr<T>::smart_ptr(T *p)
   : _obj(p), _counter(new int(1))
{
}
 
template <class T>
inline void smart_ptr<T>::try_destroy()
{
   if (!_obj)
       return;
 
   if ((*_counter) == 1) {
       delete _counter;
       _counter = 0;
       delete _obj;
       _obj = 0;
   }
}
 
template <class T>
inline smart_ptr<T>::~smart_ptr()
{
   try_destroy();
}
 
template <class T>
inline bool smart_ptr<T>::is_null() const
{
   return !_obj;
}
 
template <class T>
inline T* smart_ptr<T>::operator->() const
{
   return _obj;
}
 
template <class T>
inline T& smart_ptr<T>::operator*() const
{
   return *_obj;
}
 
template <class T>
inline T* smart_ptr<T>::get() const
{
   return _obj;
}
 
template <class T>
inline smart_ptr<T>& smart_ptr<T>::operator=(const smart_ptr<T> &p)
{
   if (_obj != p._obj) {
       try_destroy();
       _counter = p._counter;
       _obj = p._obj;
 
       if (_counter)
           (*_counter)++;
   }
   return *this;
}
 
template <class T>
inline smart_ptr<T>& smart_ptr<T>::operator=(T*)
{
   return *this;
}
 
template <class T>
inline bool operator==(const T *o, const smart_ptr<T> &p)
{
   return o == p.operator->();
}
 
template<class T>
inline bool operator==(const smart_ptr<T> &p, const T *o)
{
   return p.operator->() == o;
}
 
 
template <class T>
inline bool operator==(T *o, const smart_ptr<T> &p)
{
   return o == p.operator->();
}
 
template<class T>
inline bool operator==(const smart_ptr<T> &p, T *o)
{
   return p.operator->() == o;
}
 
template<class T>
inline bool operator==(const smart_ptr<T> &p1, const smart_ptr<T> &p2)
{
   return p1.operator->() == p2.operator->();
}
 
template <class T>
inline bool operator!=(const T *o, const smart_ptr<T> &p)
{
   return o != p.operator->();
}
 
template<class T>
inline bool operator!= (const smart_ptr<T> &p, const T *o)
{
   return p.operator->() != o;
}
 
 
template <class T>
inline bool operator!=(T *o, const smart_ptr<T> &p)
{
   return o != p.operator->();
}
 
template<class T>
inline bool operator!= (const smart_ptr<T> &p, T *o)
{
   return p.operator->() != o;
}
 
template<class T>
inline bool operator!= (const smart_ptr<T> &p1, const smart_ptr<T> &p2)
{
   return p1.operator->() != p2.operator->();
}
 
}
 
#endif // SMART_PTR_H
 
Как сделать теперь его тред-сейф ?

Так какой вариант: со шпионом (он же trackable в libsigc++) или через умные указатели использовать? Как идеалогически правильнее?
« Последнее редактирование: Февраль 20, 2011, 23:27 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Февраль 20, 2011, 16:11 »

А что если я хочу посылать сигналы объектам разных классов и принимать сигналы от объектов разных классов? И не думать о том каким именно объектам мне слать и получать до того момента когда наступет нужда создать соединение (уже в самом пользовательском коде)? 
А в чем помеха? Объект создается с пустыми контейнерами sender'ов (receiver'ов), connect (который так или иначе неизбежен) их заполняет
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #28 : Февраль 20, 2011, 16:26 »

А что если я хочу посылать сигналы объектам разных классов и принимать сигналы от объектов разных классов? И не думать о том каким именно объектам мне слать и получать до того момента когда наступет нужда создать соединение (уже в самом пользовательском коде)? 
А в чем помеха? Объект создается с пустыми контейнерами sender'ов (receiver'ов), connect (который так или иначе неизбежен) их заполняет
Помеха в том, что в контейнере должны будут находится объекты одного класса.
Либо сделать один абстрактный класс, но тогда придётся писать интерфейс на все случаи жизни, что не есть гут)
Идея в том, что общаться могут объекты совершенно разных классов. Задаётся лишь общий шаблон функции сигнала и слота.

Или как Вы имеете в виду?
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #29 : Февраль 21, 2011, 00:49 »

Вобщем остановился на варианте BRE: отнаследовать receiver от trackable (он же в прошлом spy), т.е. на схеме используемой в libsigc++.
Это означает, что объект который получает сигналы (receiver) должен быть отнаследован от класса trackable. trackable - автоматически разрывает соединение, если receiver будет уничтожен.

Выглядит это так:
Код
C++ (Qt)
#include <iostream>
#include <string>
#include "signal_slot.h"
 
/* Класс A испускает сигналы */
class A
{
public:
   A() {}
 
   ssc::signal<void, std::string> my_signal;
 
   void run() {
       my_signal("Hello Word!");
   }
};
 
/* Класс B  содержит слоты, поэтому он должен отнаследоваться от trackable */
class B : public ssc::trackable
{
public:
   B() {}
 
   void slot1(const std::string &str) {
       std::cout << "slot1, signal - " << str << std::endl;
   }
 
   void slot2(std::string str) const {
       std::cout << "slot2, signal - " << str << std::endl;
   }
};
 
int main()
{
   B *b = new B;
   A *a = new A;
 
   connect(a->my_signal, b, &B::slot1);
   connect(a->my_signal, b, &B::slot2);
 
   a->run();
 
   delete b;
   delete a;
 
   return 0;
}
 
 

Сам механизм сигнал-слот здесь реализован по следующей схеме:
1) Класс base_signal:
Код
C++ (Qt)
template <class T_return, class T_arg> class base_signal
 
Чисто абстрактный класс, реализующий интерфейс:
Код
C++ (Qt)
virtual T_return operator() (const T_arg &) const = 0;
virtual bool valid() const = 0;
 

2) Класс signal:
Код
C++ (Qt)
template <class T_return, class T_arg> class signal
 
Знает о всех соединениях со слотами: имеет список (std::list) соединений (manager_connection) являющихся потомками base_signal.
Имеет перегруженный оператор
Код
C++ (Qt)
T_return operator() (const T_arg &arg) const
 
 
в котором перебирается весь список соединений и для каждого объекта manager_connection вызывается свой переопределённый virtual T_return operator() (const T_arg &) const.

3) Класс manager_connection:
Код
C++ (Qt)
template <class T_receiver, class T_return, class T_arg>
class manager_connection : public base_signal<T_return, T_arg>
 
наследуется от класса base_signal и реализует весь функционал.

4) Класс trackable и trigger:
Код
C++ (Qt)
class trigger
{
public:
   trigger() : _flag(true) {}
   void set(bool flag) { _flag = flag; }
   bool get() const { return _flag; }
 
private:
   bool _flag;
};
 
class trackable
{
public:
   trackable() {
       spy = smart_ptr<trigger>(new trigger);
   }
   virtual ~trackable() {
       spy->set(false);
   }
   smart_ptr<trigger> spy;
};
 
trigger - простой класс имеющий два состояния: true - receiver жив, false - уничтожен
Класс trackable - обёртка над trigger, причём trigger заворачивается в умный указатель, который знает сколько других указателей ссылаются на объект. smart_ptr уничтожит объект если число ссылок counter == 1.
manager_connection также содержит
Код
C++ (Qt)
private:
   T_receiver *_receiver; // указатель на receiver
   smart_ptr<trigger> _spy; // шпион, он же trackable
   ...
 


При вызове одного из 4 конструктора  manager_connection происходит следующее:
Код
C++ (Qt)
manager_connection(signal<T_return, T_arg> &s, T_receiver *obj, function_type_4 slot) {
       _receiver = obj;  // копируем указатель
       _spy = _receiver->spy;  /* копируем шпиона, который вкурсе что происходит с receiverОМ
                                               по средством функции bool get() const */

       _slot_4 = slot;
       _index = 4;
       s.connect(this);  // Заносим данное соединение в список соединений нашего сигнала
   }
 
 

Конечно, в пользовательском коде реально используется только два класса: signal и trackable
и ещё один из вариантов перегруженной функции connect:
Код
C++ (Qt)
template <class T_receiver, class T_return, class T_arg>
void connect(signal<T_return, T_arg> &s, T_receiver *obj, T_return (T_receiver::*slot)(T_arg)) {
   new manager_connection<T_receiver, T_return, T_arg>(s, obj, slot);
}
 

в которой просто создаётся объект manager_connection и передаются все аргументы.

Как то так..
 
Выкладываю для тестирования файл проекта.
Немного причесал код, сейчас вроде всё работает адекватно))
 
« Последнее редактирование: Февраль 21, 2011, 02:05 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: 1 [2] 3 4 ... 8   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.787 секунд. Запросов: 22.