использовать аллокатор только для тех типов, которые это позволяют
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.03.14 11:08
Оценка:
привет!

есть препроцессорный код, который генерит десериализаторы в виде:
type1 arg0;
type2 arg1;
archive ia(...);
ia & arg0
   & arg1;


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

более полный пример:
template<typename Alloc>
struct type {
   type(Alloc &alloc)
      :alloc(alloc)
   {}

   void some_func(const char *ptr, const std::size_t size) {
      archive ia(ptr, size, alloc);
      type0 arg0;
      type1 arg1;
      ia & arg0
         & arg1;
      func(arg0, arg1);
   }

private:
   Alloc &alloc;
};

тут, обратите внимание на type0/type1 и arg0/arg1.
type0/type1 могут быть как классовыми типами, так и подами/фундаментальными.
во время кодогенерации нет возможности определить, чем на самом деле являются типы, и, следовательно, нет возможности сгенерировать нужный способ инициализации.

предложения?


спасибо.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: использовать аллокатор только для тех типов, которые это
От: Кодт Россия  
Дата: 13.03.14 12:04
Оценка: 9 (1) +1
Здравствуйте, niXman, Вы писали:

X>более полный пример:

X>
X>template<typename Alloc>
X>struct type {
X>   type(Alloc &alloc)
X>      :alloc(alloc)
X>   {}

X>   void some_func(const char *ptr, const std::size_t size) {
X>      archive ia(ptr, size, alloc);
X>      type0 arg0;
X>      type1 arg1;
X>      ia & arg0
X>         & arg1;
X>      func(arg0, arg1);
X>   }

X>private:
X>   Alloc &alloc;
X>};
X>

X>тут, обратите внимание на type0/type1 и arg0/arg1.

Обратил, ну и где там аллокатор?
Предполагалось, что должно быть
X>   void some_func(const char *ptr, const std::size_t size) {
X>      archive ia(ptr, size, alloc);
X>      type0 arg0;        // не знает про аллокатор
X>      type1 arg1(alloc); // использует аллокатор
X>      ia & arg0
X>         & arg1;
X>      func(arg0, arg1);
X>   }


Да?

Делаем вот так
with_allocator<type0, Alloc> arg0(alloc);
with_allocator<type1, Alloc> arg1(alloc);
ia & *arg0
   & *arg1
   ;
func(*arg0, *arg1);

где
template<class T, class A, bool WithA> struct with_allocator_base;

template<class T, class A> struct with_allocator_base<T,A,true>
{
  T var;
  explicit with_allocator_base(A& a) : var(a) {}
  T& operator() { return var; }
};
template<class T, class A> struct with_allocator_base<T,A,false>
{
  T var;
  explicit with_allocator_base(A& a) {}
  T& operator() { return var; }
};

template<class T, class A> struct with_allocator : with_allocator_base<T,A, has_constructor<T,A>::value >
{
  typedef with_allocator_base<T,A, is_constructible_from<T,A>::value > base;
  explicit with_allocator(A& a) : base(a) {}
};


Если типы копи-конструируемые, то можно и проще
template<class T, class A> auto make(A& a) -> enable_if< is_constructible<T,A>::value, T >::type { return T(a); }
template<class T, class A> auto make(A& a) -> enable_if<!is_constructible<T,A>::value, T >::type { return T( ); }

......

type0 arg0 = make<type0>(alloc);
type1 arg1 = make<type1>(alloc);
Перекуём баги на фичи!
Re[2]: использовать аллокатор только для тех типов, которые это
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.03.14 13:08
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Предполагалось, что должно быть

...
К>Да?
да.

идею понял, спасибо!
нужно подумать...

К>Если типы копи-конструируемые, то можно и проще

нет, нет нужды копировать.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: использовать аллокатор только для тех типов, которые это
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.03.14 13:14
Оценка:
еще вот такой traits, оказывается, есть:
http://en.cppreference.com/w/cpp/memory/uses_allocator
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: использовать аллокатор только для тех типов, которые это
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.03.14 13:26
Оценка:
Здравствуйте, Кодт, Вы писали:

поясни плиз этот фрагмент кода.

К>
К>template<class T, class A> struct with_allocator : with_allocator_base<T,A, has_constructor<T,A>::value > {
К>  typedef with_allocator_base<T,A, is_constructible_from<T,A>::value > base;
К>  explicit with_allocator(A& a) : base(a) {}
К>};
К>

в первой строке ты наследуешь конкретный with_allocator_base. но во второй строке ты определяешь тип base, который, возможно специализируется по другому условию, ибо: 'is_constructible_from<T,A>::value' и 'has_constructor<T,A>::value' — разные шаблоны. или тут опечатка?

и то, что ты выполняешь во второй и третьей строке, насколько я понимаю, можно заменить так?:
using with_allocator_base<T,A, has_constructor<T,A>::value>with_allocator_base;

(тыц, третий фрагмент кода)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: использовать аллокатор только для тех типов, которые
От: Кодт Россия  
Дата: 13.03.14 20:55
Оценка: 6 (1) +1
Здравствуйте, niXman, Вы писали:

X>в первой строке ты наследуешь конкретный with_allocator_base. но во второй строке ты определяешь тип base, который, возможно специализируется по другому условию, ибо: 'is_constructible_from<T,A>::value' и 'has_constructor<T,A>::value' — разные шаблоны. или тут опечатка?


Опечатка, конечно. Я же испытывал на кошках — набросал эскиз в нотепаде и скомпилировал 2010 студией. После чего вспомнил, что велосипедирую, в 11 стандарте уже есть нужная метафункция, и переписал... но недопереписал


X>и то, что ты выполняешь во второй и третьей строке, насколько я понимаю, можно заменить так?:

X>using with_allocator_base<T,A, has_constructor<T,A>::value>with_allocator_base;

Да. Потому что у меня основной компилятор — это VS2010, а С++11 это для души, и редкоиспользуемые фичи я не всегда вспоминаю; зато очень быстро печатаю десятью пальцами

На самом деле, всё проще: надо протащить SFINAE в конструкторЫ обёртки
template<class T> struct with_allocator
{
    struct unspecified_type; // от греха подальше: чтобы никто не передавал второй параметр в конструктор

    T var;
    T& operator*() { return var; }
    T const& operator*() { return var; }

    template<class A>
    explicit with_allocator(A& a,
         typename enable_if< is_constructible<T,A&>::value, unspecified_type* >::type _ = nullptr)
    : var(a)
    {}
    
    template<class A>
    explicit with_allocator(A& a,
         typename enable_if<!is_constructible<T,A&>::value, unspecified_type* >::type _ = nullptr)
    {}
};

http://ideone.com/8fwXl9
Перекуём баги на фичи!
Re[4]: использовать аллокатор только для тех типов, которые
От: niXman Ниоткуда https://github.com/niXman
Дата: 14.03.14 08:34
Оценка:
Здравствуйте, Кодт, Вы писали:

понятно.

спасибо, вопрос закрыт!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.