member function as template argument (VC6) workaround?
От: Andrew S Россия http://alchemy-lab.com
Дата: 22.01.04 16:19
Оценка:
Всем доброго времени суток.

Надоело постоянно писать статические функции-прокси для вызова функций-членов класса в отдельном потоке, захотелось это дело как то автоматизировать. Вот такой код вполне валиден, однако на VC6 не компилится (точнее, не инстанцируется):

template <class T, int (T::*f)()>    
struct CProxy
{
    static int ThreadProcStub(T *p)
    {
        return (p->*f)();
    }
};


class A
{
public:
  int onA()
  {
    return 1;
  };
  int onB()
  {
    return 2;
  };
};

int (*f)(A *) = &CProxy<A, &A::onA>::ThreadProcStub; // invalid template argument

На "правильных" компиляторах, конечно, все ОК. Есть ли какой обходной путь добиться такого (т.е. фактически генерации нужной статической функции на основе типа класса и адреса его функции-члена) на VC6?
Спасибо.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: member function as template argument (VC6) workaround?
От: Павел Кузнецов  
Дата: 22.01.04 16:23
Оценка: 12 (1)
Здравствуйте, Andrew, Вы писали:

AS> такой код вполне валиден, однако на VC6 не компилится

AS> (точнее, не инстанцируется):

AS>
 AS> template <class T, int (T::*f)()>
 AS> struct CProxy
 AS>


http://rsdn.ru/Forum/?mid=136339
Автор: Павел Кузнецов
Дата: 21.11.02


Т.е. сделать искуственный вложенный шаблон класса с одним параметром —
указателем на член.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: member function as template argument (VC6) workaround
От: Andrew S Россия http://alchemy-lab.com
Дата: 22.01.04 17:46
Оценка:
ПК>Т.е. сделать искуственный вложенный шаблон класса с одним параметром —
ПК>указателем на член.

Верно... И ведь уже раньше так делал, да и пост этот тоже видел. День,наверное, не задался
Только вот до сих пор для меня загадка, в чем VC видит отличие между этими вариантами. Шаманство, в общем
Павел, большое спасибо!
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re: member function as template argument (VC6) workaround?
От: MaximE Великобритания  
Дата: 22.01.04 19:18
Оценка: 7 (2) +1
Andrew S wrote:

> Надоело постоянно писать статические функции-прокси для вызова функций-членов класса в отдельном потоке, захотелось это дело как то автоматизировать.


Радикальное решение — boost::threads. В качестве бонуса получаешь все прелести boost::bind.

--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/
Posted via RSDN NNTP Server 1.8 beta
Re[2]: небольшой оффтоп
От: ArtDenis Россия  
Дата: 22.01.04 19:37
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Радикальное решение — boost::threads. В качестве бонуса получаешь все прелести boost::bind.


Лично мне концепция boost::threads кажется неудобной (по стилю ассоциации данных с потоками). Может быть потому, что я привык к потокам в стиле VCL

Хотя конкретно для данной задачи boost::threads подходят идеально.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: небольшой оффтоп
От: Andrew S Россия http://alchemy-lab.com
Дата: 22.01.04 20:12
Оценка: :)
ME>>Радикальное решение — boost::threads. В качестве бонуса получаешь все прелести boost::bind.

AD>Лично мне концепция boost::threads кажется неудобной (по стилю ассоциации данных с потоками). Может быть потому, что я привык к потокам в стиле VCL


AD>Хотя конкретно для данной задачи boost::threads подходят идеально.


Потоки в стиле VCL — это ужасное решение. Да прибудет с ними гиена огненная, пусть сгинут во мраке ада. Аминь.

А по поводу boost::threads скажу лишь одно — не плодите сущности без необходимости. Но за совет спасибо, будет время — ознакомлюсь.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[4]: небольшой оффтоп
От: ArtDenis Россия  
Дата: 22.01.04 20:14
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Потоки в стиле VCL — это ужасное решение. Да прибудет с ними гиена огненная, пусть сгинут во мраке ада. Аминь.




Давно так не смеялся
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: небольшой оффтоп
От: MaximE Великобритания  
Дата: 22.01.04 23:01
Оценка:
On Thu, 22 Jan 2004 19:37:35 GMT, ArtDenis <15178@news.rsdn.ru> wrote:

> Здравствуйте, MaximE, Вы писали:

>
> ME>Радикальное решение — boost::threads. В качестве бонуса получаешь все прелести boost::bind.
>
> Лично мне концепция boost::threads кажется неудобной (по стилю ассоциации данных с потоками). Может быть потому, что я привык к потокам в стиле VCL

Непонятно "ассоциации данных с потоками". Объект потока не обязательно сохранять, т.к. разрушение этого объекта не завершает поток.

--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/
Posted via RSDN NNTP Server 1.8 beta
Re[4]: небольшой оффтоп
От: ArtDenis Россия  
Дата: 23.01.04 04:53
Оценка:
Здравствуйте, MaximE, Вы писали:

>> Лично мне концепция boost::threads кажется неудобной (по стилю ассоциации данных с потоками). Может быть потому, что я привык к потокам в стиле VCL

ME>Непонятно "ассоциации данных с потоками".

Извиняюсь, слишком кратко написал. Представь себе, что ты пишешь многопоточный сервер. На одно подключение клиента — один поток. Для каждого потока — свой набор данных. В VCL это всё делалось элементарно: ты наследовался от класса потока, добавлял свои данные, а затем с ними работал. А как это сделано в boost::threads? Через thread_specific_ptr. Вот пример из буста:
#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>
#include <cassert>

boost::thread_specific_ptr<int> value;

void increment()
{
    int* p = value.get();
    ++*p;
}

void thread_proc()
{
    value.reset(new int(0)); // initialize the thread's storage
    for (int i=0; i<10; ++i)
    {
        increment();
        int* p = value.get();
        assert(*p == i+1);
    }
}

int main(int argc, char* argv[])
{
    boost::thread_group threads;

    for (int i=0; i<5; ++i)
        threads.create_thread(&thread_proc);
    threads.join_all();
}


IMHO, это просто убожество. Данный недостаток перекрывает все удобства boost::threads. Поправте меня, если я не прав.

Денис.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[5]: небольшой оффтоп
От: Xor.  
Дата: 23.01.04 09:34
Оценка:
AD>Извиняюсь, слишком кратко написал. Представь себе, что ты пишешь многопоточный сервер. На одно подключение клиента — один поток. Для каждого потока — свой набор данных. В VCL это всё делалось элементарно: ты наследовался от класса потока, добавлял свои данные, а затем с ними работал. А как это сделано в boost::threads? Через thread_specific_ptr. Вот пример из буста:

Ну тут тоже можно создать объект:

class Thread{
boost::thread thr;
void main(){/*do it*/}
public:
Thread():thr(main){}
~Thread(){ thr.join(); }
};

main(){
std::vector tv(10);
}

PS. вообще-то я очень поверхностно знаю boost, поэтому возможно, что есть варианты и получше.
Re: member function as template argument (VC6) workaround?
От: Кодт Россия  
Дата: 23.01.04 10:22
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Всем доброго времени суток.


AS>Надоело постоянно писать статические функции-прокси для вызова функций-членов класса в отдельном потоке, захотелось это дело как то автоматизировать.


Почему бы не воспользоваться boost?
class thread_launcher
{
public:
  typedef boost::function0<void> func_type;
private:
  static int thunk(void* pv)
  {
    *pbf = (func_type*)pv;
    (*pbf)();
    delete pbf;
  }
public:
  static unsigned long launch(const func_type& fn)
  {
    return beginthread(thunk, 0, new func_type(fn));
  }
  template<class C>
  static unsigned long launch(C* pobj, void(&C::method)())
  {
    return launch(func_type(pobj, method));
  }
};
Перекуём баги на фичи!
Re[2]: member function as template argument (VC6) workaround
От: ArtDenis Россия  
Дата: 23.01.04 11:45
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Почему бы не воспользоваться boost?


Тогда уж можно пойти дальше и использовать boost::threads, как это советовал MaximE:
class C
{
public:
  void thread_func(int arg1, int arg2)
  {
    Beep(arg1, arg2); // :)
  }
};

C c;

int main(int argc, char* argv[])
{
  boost::thread thrd( boost::bind(C::thread_func, &c, 1000, 200) );

  thrd.join();
}
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: member function as template argument (VC6) workaround
От: Xor.  
Дата: 23.01.04 12:05
Оценка:
AD>Тогда уж можно пойти дальше и использовать boost::threads, как это советовал MaximE:
AD>
AD>class C
AD>{
AD>public:
AD>  void thread_func(int arg1, int arg2)
AD>  {
AD>    Beep(arg1, arg2); // :)
AD>  }
AD>};

AD>C c;

AD>int main(int argc, char* argv[])
AD>{
AD>  boost::thread thrd( boost::bind(C::thread_func, &c, 1000, 200) );

AD>  thrd.join();
AD>}
AD>


Да MaximE конечно красиво записал, но это не addresed to the problem.

Связь данных и потока так и остаётся за кадром.
Когда можно разрушить объект `С`? Из кода не ясно.
Данная схема позволяет запустить несколько параллельных потоков метода одного и того же объекта, что видимо далеко не всегда желаемо if at all.

Как я уже написал в предыдущем посте (правда забыл в инициализации привязаться через bind :-) различные схемы решения таких проблем вполне можно решить используя и бустовские классы.

Вопрос — стоило ли добавлять в boost такие обвязки?
Re[4]: member function as template argument (VC6) workaround
От: ArtDenis Россия  
Дата: 23.01.04 12:15
Оценка:
Здравствуйте, Xor., Вы писали:

X>Да MaximE конечно красиво записал, но это не addresed to the problem.

X>Связь данных и потока так и остаётся за кадром.
X>Когда можно разрушить объект `С`? Из кода не ясно.

Судя по всему, AndrewS сам контролирует жизнь объекта класса. В данном случае использование boost::threads позволяет отказаться от использования статических функций в классе для запуска потока.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: небольшой оффтоп
От: ArtDenis Россия  
Дата: 23.01.04 12:23
Оценка:
Здравствуйте, Xor., Вы писали:

X>class Thread{
X>      boost::thread thr;
X>      void main(){/*do it*/}
X>public:
X>      Thread():thr(main){}
X>      ~Thread(){ thr.join(); }
X>};

X>main(){
X>    std::vector tv(10);
X>}


Интересный код, я так и не понял, что он делает

X>PS. вообще-то я очень поверхностно знаю boost, поэтому возможно, что есть варианты и получше.

Конечно же есть. В моём верхнем сообщении я как раз привёл пример из буста с таким решением. Просто лично мне оно не нравится.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[5]: member function as template argument (VC6) workaround
От: Andrew S Россия http://alchemy-lab.com
Дата: 23.01.04 12:40
Оценка:
AD>Судя по всему, AndrewS сам контролирует жизнь объекта класса. В данном случае использование boost::threads позволяет отказаться от использования статических функций в классе для запуска потока.

Именно так. Более того, совершенно нежелательно ассоциировать экземпляр класса с потоком, т.к. потоков у одного экземпляра может быть и несколько, и они выполняют совершенно разные задачи. Судя по всему, реализовать это при помощи boost::threads очень даже можно, но так уж получается, что я предпочитаю не использовать высокоуровневые обертки там, где без этого можно обойтись. И бью других по рукам за излишнее усложнение кода там, где можно обойтись более простыми и архитектурно чистыми решениями.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[4]: member function as template argument (VC6) workaround
От: MaximE Великобритания  
Дата: 23.01.04 17:49
Оценка:
Xor. wrote:

> Да MaximE конечно красиво записал, но это не addresed to the problem.


Насколько я понимаю, проблема была вызвать ф-цию член в отдельном потоке. boost::treads решает эту проблему. Или я что-то упускаю?

> Связь данных и потока так и остаётся за кадром.


Так и не понял смысл фразы "Связь данных и потока". Что это значит, что хорошо, что плохо?

> Когда можно разрушить объект `С`? Из кода не ясно.


Из кода ясно, что экземпляр класса C c — глобальный объект. Также ясно, что main() не вернет управления, пока не завершиться поток, направленный в функцию-член c.

> Данная схема позволяет запустить несколько параллельных потоков метода одного и того же объекта, что видимо далеко не всегда желаемо if at all.


Это преимущество данной схемы — не накладывает ограничений.

В ACE, например, чтобы направить поток в ф-цию-член, надо отнаследоваться от класса потока, и реализовать виртуальную ф-цию-член Run() (или что-то наподобие). Я если я хочу два потока в разные ф-ции-члены? Придется приложить усилия, чтобы сделать это при помощи такой схемы. (не говоря о том, что добавленние vtable в класс может быть не очень желательным)

> Как я уже написал в предыдущем посте (правда забыл в инициализации привязаться через bind различные схемы решения таких проблем вполне можно решить используя и бустовские классы.

>
> Вопрос — стоило ли добавлять в boost такие обвязки?

Какие именно "обвязки"? Если имеешь в виду boost::threads, то это не просто обвязки — эту мультиплатформенные обвязки (по крайней мере win32, POSIX, MAC), которые часто позволяют не опускаться до уровня API платформы.

--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/
Posted via RSDN NNTP Server 1.8 beta
Re[6]: member function as template argument (VC6) workaround
От: MaximE Великобритания  
Дата: 23.01.04 18:18
Оценка:
Andrew S wrote:

> AD>Судя по всему, AndrewS сам контролирует жизнь объекта класса. В данном случае использование boost::threads позволяет отказаться от использования статических функций в классе для запуска потока.

>
> Именно так. Более того, совершенно нежелательно ассоциировать экземпляр класса с потоком, т.к. потоков у одного экземпляра может быть и несколько, и они выполняют совершенно разные задачи.

Не вижу связи, между частями сложного предложения. Понятия класс/экземпляр и поток совершенно ортогональны. Класс, данном контексте, — способ организации исходного кода. Поток — сущность, которая исполняет код.

Экземпляр класса может создать хоть M, или даже N потоков и направить их куда ему нужно.

> Судя по всему, реализовать это при помощи boost::threads очень даже можно, но так уж получается, что я предпочитаю не использовать высокоуровневые обертки там, где без этого можно обойтись. И бью других по рукам за излишнее усложнение кода там, где можно обойтись более простыми и архитектурно чистыми решениями.


Это вы, батенька, очень напрасно. boost::threads элегантно и эффективно решает рутинную задачу создания потоков. boost::threads документирован и его назначение недвусмысленно. ИМХО, намного проще читать и понимать код, который оперирует стандартными высокоуровневыми сущностями, чем код, который реализует те же задачи посредством низкоуровневых API вызовов.

Кроме того, использование сущностей высокого уровня позволяет инженеру сосредоточиться на problem domain, а не на том, например, в каком параметре передать указатель на ф-цию в вызове CreateThread() и не забыть проверить и правильно интерпретировать возвращаемое значение.

--
Maxim Egorushkin
MetaCommunications Engineering
http://www.meta-comm.com/engineering/
Posted via RSDN NNTP Server 1.8 beta
Re[5]: небольшой оффтоп
От: ArtDenis Россия  
Дата: 23.01.04 18:20
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>...


Хотя я, конечно, погррячился.

Никто не мешает вызывать boost::thread_specific_ptr::get, а затем использовать это значение.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: небольшой оффтоп
От: ArtDenis Россия  
Дата: 23.01.04 18:22
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Хотя я, конечно, погррячился.

А теперь поторопился: Хотел написать:

Никто не мешает вызывать boost::thread_specific_ptr::get один раз, а затем использовать это значение сколько угодно и где угодно в потоке.
... << RSDN@Home 1.1.2 stable >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.