Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 18.08.07 10:29
Оценка:
Здравствуйте.

Имеется шаблон:

template<class T>
T** F(T *p) {

  static T *sptr=0;

  sptr=p;
  return &sptr;
}


Требуется для любого типа T создавать новое тело функции, даже для одного и того же типа.
те:

pp1=F<int>(p1);
pp2=F<int>(p2);
pp3=F<float>(p3);
// здесь pp1 pp2 и pp3 должны иметь разные адреса


Возможно ли такое сделать в принципе?

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

Преведствуются любые решения, даже с использованием MS specific фичек.
Re: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 18.08.07 10:31
Оценка:
Забыл сказать, компилятор VS2005
Re: Шаблонная функция как генератор переменных
От: _nn_ www.nemerleweb.com
Дата: 18.08.07 10:36
Оценка: 3 (1)
Здравствуйте, unreg_flex, Вы писали:

_>Возможно ли такое сделать в принципе?


_>Может нужно завести дополнительный параметр в шаблоне (например int),

_>но как при каждом инстанцировании увеличивать его на 1 ума не приложу.

_>Преведствуются любые решения, даже с использованием MS specific фичек.


Можно взять на использование __COUNTER__ (MS. spec.)
Переносимее и менее работающее будет __LINE__.

Что-то типа:
template<int N, typename T>
T** f_impl(T *p)
{
  static T *sptr = p;
  return &sptr;
}

template<typename T>
T** f(T* p)
{
  return f_impl<__COUNTER__>(p);
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Шаблонная функция как генератор переменных
От: alexeiz  
Дата: 18.08.07 10:42
Оценка:
Здравствуйте, _nn_, Вы писали:

__>template<typename T>

__>T** f(T* p)
__>{
__> return f_impl<__COUNTER__>(p);
__>}
__>[/c]

__COUNTER__ генерируется препроцессором и подставляется до начала компиляции.
Re[3]: Шаблонная функция как генератор переменных
От: _nn_ www.nemerleweb.com
Дата: 18.08.07 10:46
Оценка:
Здравствуйте, alexeiz, Вы писали:

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


__>>template<typename T>

__>>T** f(T* p)
__>>{
__>> return f_impl<__COUNTER__>(p);
__>>}
__>>[/c]

A>__COUNTER__ генерируется препроцессором и подставляется до начала компиляции.


Можно сделать функцию f макросом %)
Или же вызывать f_impl напрямую подставляю __COUNTER__.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Шаблонная функция как генератор переменных
От: Roman Odaisky Украина  
Дата: 18.08.07 10:54
Оценка:
Здравствуйте, unreg_flex, Вы писали:

_>Требуется для любого типа T создавать новое тело функции, даже для одного и того же типа.


А что мешает использовать динамическую память? Например, просто создавать и возвращать boost::shared_ptr?

Назови свою конечную цель, и тогда тебе смогут помочь более обоснованно.

_>Преведствуются любые решения, даже с использованием MS specific фичек.


А такие словесы здесь не приветствуются.
До последнего не верил в пирамиду Лебедева.
Re[2]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 18.08.07 11:43
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>А что мешает использовать динамическую память? Например, просто создавать и возвращать boost::shared_ptr?


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

RO>Назови свою конечную цель, и тогда тебе смогут помочь более обоснованно.


Уже помогли
Re[2]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 18.08.07 11:49
Оценка:
Здравствуйте, _nn_, Вы писали:

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


_>>Возможно ли такое сделать в принципе?


_>>Может нужно завести дополнительный параметр в шаблоне (например int),

_>>но как при каждом инстанцировании увеличивать его на 1 ума не приложу.

_>>Преведствуются любые решения, даже с использованием MS specific фичек.


__>Можно взять на использование __COUNTER__ (MS. spec.)

Почитал, попробовал, получилось
Полезная штучка, жаль что нестандартно, ну да ладно.
Особенно понравилось, что теперь полностью самому можно управлять специализацией.
Хочу совпадает, нехочу не совпадает

__>Переносимее и менее работающее будет __LINE__.


Это к сожалению примерно как #define TRUE (rand()%10000)
Re[3]: Шаблонная функция как генератор переменных
От: Evgeniy13 Россия  
Дата: 19.08.07 08:39
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>__COUNTER__ генерируется препроцессором и подставляется до начала компиляции.


А разве __COUNTER__ не обнуляется при каждом новом модуле?
Не все в этом мире можно выразить с помощью нулей и единиц...
Re[4]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 19.08.07 09:23
Оценка:
Здравствуйте, Evgeniy13, Вы писали:

E>А разве __COUNTER__ не обнуляется при каждом новом модуле?


Обнуляется

Как кто-то тут говорил, компилятор в очередной раз ограничил полет мысли.
Re: Шаблонная функция как генератор переменных
От: igna Россия  
Дата: 19.08.07 13:34
Оценка:
Здравствуйте, unreg_flex, Вы писали:

_>Преведствуются любые решения, даже с использованием MS specific фичек.


template<class T, class Tag>
T** F(T *p) {

  static T *sptr=0;

  sptr=p;
  return &sptr;
}


class my_tag {};
pp1=F<int, my_tag>(p1);
class another_tag {};
pp2=F<int, another_tag>(p2);
class yet_another_tag {};
pp3=F<float, yet_another_tag>(p3);
Re: Шаблонная функция как генератор переменных
От: remark Россия http://www.1024cores.net/
Дата: 19.08.07 20:51
Оценка: 1 (1)
Здравствуйте, unreg_flex, Вы писали:

_>Возможно ли такое сделать в принципе?


_>Может нужно завести дополнительный параметр в шаблоне (например int),

_>но как при каждом инстанцировании увеличивать его на 1 ума не приложу.

_>Преведствуются любые решения, даже с использованием MS specific фичек.


http://www.rsdn.ru/forum/message/2337951.1.aspx
Автор: remark
Дата: 06.02.07



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Шаблонная функция как генератор переменных
От: Bell Россия  
Дата: 20.08.07 09:48
Оценка: +1
Здравствуйте, unreg_flex, Вы писали:

Если нужен просто новый адрес, то можно, к примеру, так:
template<class T>

T** F(T *p) {

  static std::list<T*> lst;
  lst.push_back(p);

  return &lst.back();
}
Любите книгу — источник знаний (с) М.Горький
Re: Шаблонная функция как генератор переменных
От: Кодт Россия  
Дата: 20.08.07 11:06
Оценка: +1
Здравствуйте, unreg_flex, Вы писали:

<>

А тебе нужны именно функции?
Может быть, без лишних хаков, будет правильнее на объектах?
template<class T>
struct F
{
    T* ptr;
    F(T* p0 = NULL) : ptr(p0) {}
    T** reset()(T* p) { *ptr = p; return &ptr; }
};

.....
pp1 = new F<int>();
pp2 = new F<int>();
.....
pp1->reset(new int());
.....

Если привлечь boost::bind / boost::function / boost::shared_ptr, то можно избавиться от ->reset.
function<int**(*)(int*)> f1 = bind(&F<int>::reset, shared_ptr(new F<int>()), _1);

// или так
template<class T> struct Ftraits
{
    typedef T* ptr_type;
    typedef F<T> obj_type;
    typedef shared_ptr<obj_type> objptr_type;
    typedef ptr_type*(*signature_type)(ptr_type);
    typedef function<signature_type> function_type;
    
    static function_type make(ptr_type p=NULL)
    {
        return bind(&obj_type::reset, objptr_type(new obj_type(p)), _1);
    }
};

FTraits<int>::function_type f1 = FTraits<int>::make();

Но думаю, что избавляться не надо и даже нежелательно. Потому что приведение к указателю на функцию (будь то сишная или бустовская) маскирует семантику. А у тебя довольно специфичная вещь, чтобы абстрагироваться от неё.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 28.08.07 12:33
Оценка:
Здравствуйте, Кодт, Вы писали:

[skipped]

Это все конечно очень хорошо и понятно, только вот ни reset ни delete ... некому будет вызывать

Суть в следующем:
Пользователь вызывает некоторый шаблонный метод A и передает в параметрах указатель на объект, этот метод инстанцирует другой шаблонный метод B, в недрах которого нужен этот указатель, но параметры метода B пофиксены и в дальнейшем берется его адрес (указатель на метод) и засовывается в список, поэтому никакие биндеры тут не пройдут. Список параметров метода B менять нельзя. Однако хочется при его инстанцировании зашить в его тело этот указатель.

Я сам прекрасно понимаю что можно сделать всякоразные списочки указателей, шаред_птр-ы и прочее, но нехочется для рубки березки использовать лазерную пушку

Пока на данный момент лучшее решение это умный указатель.

В принципе это все не к спеху и особо никому не надо, это так, программирование для удовольствия, хочется найти красивое решение без оверхеда.
Re[2]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 28.08.07 12:36
Оценка:
Здравствуйте, igna, Вы писали:

[skipped]

Осталось написать генератор ет_ановер_тагов
Re[2]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 28.08.07 12:38
Оценка:
Здравствуйте, remark, Вы писали:

R>http://www.rsdn.ru/forum/message/2337951.1.aspx
Автор: remark
Дата: 06.02.07


R>


Пока не разобрался о чем там речь, но интересно, спасибо за ссылку, читаю...
Re[5]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 28.08.07 12:46
Оценка:
Здравствуйте, unreg_flex, Вы писали:

_>Обнуляется


В принципе, как оказалось, страшно даже не то что он обнуляется в каждом модуле,
а то что написав:

template< class T >
void f() {
  ...
  g< T,__COUNTER__ >();
  ...
}


при инстанцировании f любым типом, будем всегда получать вызов g< T,0 >();
т.е. __COUNTER__ не будет менятся, поскольку он используется один раз.
Поэтому его надо будет явно передавать, или использовать макрос, ни того ни другого нехочу
Re[3]: Шаблонная функция как генератор переменных
От: Кодт Россия  
Дата: 28.08.07 13:13
Оценка: 3 (1)
Здравствуйте, unreg_flex, Вы писали:

_>Суть в следующем:

_>Пользователь вызывает некоторый шаблонный метод A и передает в параметрах указатель на объект, этот метод инстанцирует другой шаблонный метод B, в недрах которого нужен этот указатель, но параметры метода B пофиксены и в дальнейшем берется его адрес (указатель на метод) и засовывается в список, поэтому никакие биндеры тут не пройдут. Список параметров метода B менять нельзя. Однако хочется при его инстанцировании зашить в его тело этот указатель.

Отвратительное описание задачи. Намертво перемешаны время компиляции и время исполнения. Зачем, почему...

Множество вызовов метода с одинаковой сигнатурой приводят к созданию ровно одного воплощения шаблона. Поэтому получить множество объектов только средствами компилятора (размещённых в static storage) — не выйдет.

Или выйдет с хаками, работающими в пределах одной единицы трансляции.
О, кстати! Пришла в голову идея хака, действующего глобально. Точнее, обеспечивающего независимость между единицами трансляции.
// f.h

namespace { // unnamed
    template<int N> struct unique_tag{};
}
#define UNIQUE_TAG unique_tag< __COUNTER__ >


template<class Tag>
struct traits
{
    template<class T>
    T** fun(T* v)
    {
        static T var = 0;
        delete var;
        var = v;
        return &var;
    }
};
#define FUN traits< UNIQUE_TAG >::fun

// a.cpp
#include "f.h"

.....
int** ppx = FUN(new int); // traits< unnamed_a::unique_tag<0> >::fun<int>
int** ppy = FUN(new int); // traits< unnamed_a::unique_tag<1> >::fun<int>
.....

// b.cpp
#include "f.h"

.....
int** ppz = FUN(new int); // traits< unnamed_b::unique_tag<0> >::fun<int>
int** ppt = FUN(new int); // traits< unnamed_b::unique_tag<1> >::fun<int>
.....

int** ptrs[3];
for(int i=0; i!=3; ++i) ptrs[i] = FUN(new int); // traits< unnamed_b::unique_tag<2> >::fun<int>
// т.е. при инициализации в цикле - получим указатели на один и тот же объект var.

void foo(int**(*f)(int*))
{
    int** ppa = f(new int);
    int** ppb = f(new int);
}
foo(FUN); // и здесь внутри foo будет фигурировать один и тот же traits< unnamed_b::unique_tag<3> >::fun<int>

Обрати внимание на два последних случая.
Если это то, что тебе хочется — используй compile-time-размещение объектов.
Если же тебе хочется, чтобы все объекты были уникальны — не заморачивай голову, делай в run-time. Например, со списками.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: Шаблонная функция как генератор переменных
От: unreg_flex  
Дата: 28.08.07 14:32
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Отвратительное описание задачи. Намертво перемешаны время компиляции и время исполнения. Зачем, почему...


Согласен, спешил, да и с терминологией у меня плохо

К>Множество вызовов метода с одинаковой сигнатурой приводят к созданию ровно одного воплощения шаблона. Поэтому получить множество объектов только средствами компилятора (размещённых в static storage) — не выйдет.


Вот это и плохо
Почитал пост с хаком через friend, плохо понял как это работает, да и оставлять такое в коде страшно.
Хотя возможности такой штучки действительно впечатляют.
Видимо не используя хаков, без динамической памяти тут не обойтись.

Приведу код, надеюсь так будет понятней:

typedef bool (Manager::*Listener)(double data);

class Manager {

public:

  void AddListener(int nSlot,Listener pListener) {
    // тут производится добавление pListener в некоторый список
    ...
  }

  ...
}


Этот класс менять нельзя.

Но хочется добавить в класс производный от Manager несколько методов, которые будут автоматически
генерировать некорые часто используемые типы Listener-ов (дабы не писать их каждый раз ручками),
например так:

class CoolManager: public Manager {

public:

  template< class Object >
  void AddCoolListener(int nSlot,Object *pObject) {
    Manager::AddListener(nSlot,&CoolManager::CoolListener< Object >);
  }

  ...

private:

  template< class Object >
  bool CoolListener(double data) {
    // проблема в том что тут нужен указатель pObject, которая передается в AddCoolListener
    // по сути ее надо сюда как-то зашить
    // но использовать динамическую память или списки не очень хочется
  }
}


Хочу что-бы юзер писал без макросов:
SomeManager1.AddCoolListener(SomeSlot1,&SomeObject1);
SomeManager2.AddCoolListener(SomeSlot2,&SomeObject2);

Идея заключалась в использовании шаблонной функции со статической переменной внутри
для хранения в ней указателя pObject. Но юзер каждый раз передает разные указатели.
Число этих указателей равно числу вызовов AddCoolListener< ... >,
вот я и хотел заставить компилятор при каждом вызове AddCoolListener генерировать новую
копию CoolListener и функцию с новым статическим указателем внутри (для использования внутри CoolListener)

К>О, кстати! Пришла в голову идея хака, действующего глобально. Точнее, обеспечивающего независимость между единицами трансляции.


Вот за это +3, хоть проблему это не решает (есть макросы), но это интересный способ увеличить диапазон действия __COUNTER__.
Вроде просто, но сам я не догадался
Кстати, а почему это хак???
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.