хитрая конструкция
От: Hard_Club  
Дата: 06.03.15 11:48
Оценка: +1 -2
что обозначает данная конструкция:

template <class F, class... Args>
    void fa(F f, Args&&... args) {
        [](...){}((f(std::forward<Args>(args)), 0)...);
}
Re: хитрая конструкция
От: niXman Ниоткуда https://github.com/niXman
Дата: 06.03.15 11:50
Оценка:
может быть ты уже хоть раз прочтешь книжку?!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: хитрая конструкция
От: Nikе Россия  
Дата: 06.03.15 12:32
Оценка:
Здравствуйте, Hard_Club, Вы писали:

H_C>что обозначает данная конструкция:


Вызвать функцию f для каждого аргумента функции fa.
Непонятно зачем так сложно, и оно ведёт себя по разному на разных компиляторах.
Нужно разобрать угил.
Re[2]: хитрая конструкция
От: niXman Ниоткуда https://github.com/niXman
Дата: 06.03.15 12:34
Оценка:
Здравствуйте, Nikе, Вы писали:

N>оно ведёт себя по разному на разных компиляторах.

приведите пример.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: хитрая конструкция
От: Nikе Россия  
Дата: 06.03.15 12:38
Оценка: 2 (1)
Здравствуйте, niXman, Вы писали:

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


N>>оно ведёт себя по разному на разных компиляторах.

X>приведите пример.

template <class F, class... Args> void fa( F f, Args&&... args )
{
    []( ... ) {}( ( f( std::forward<Args>( args ) ), 0 )... );
}

fa( []( int a ) { cout << a ); }, 1, 2, 3, 4, 5 );


VS 2015 и GCC 4.91: 54321

CLang 6.0.56: 12345
Нужно разобрать угил.
Re[4]: хитрая конструкция
От: niXman Ниоткуда https://github.com/niXman
Дата: 06.03.15 12:40
Оценка:
Здравствуйте, Nikе, Вы писали:

N>VS 2015 и GCC 4.91: 54321


N>CLang 6.0.56: 12345


так вы об этом)
это нормально, и прописано в стандарте.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: хитрая конструкция
От: Abyx Россия  
Дата: 06.03.15 12:41
Оценка:
Здравствуйте, Hard_Club, Вы писали:

H_C>
H_C>template <class F, class... Args>
H_C>    void fa(F f, Args&&... args) {
H_C>        [](...){}((f(std::forward<Args>(args)), 0)...);
H_C>}
H_C>


это неправильная конструкция, f вызовется для аргументов в произвольном порядке.
правильно использовать массив или список инициализации
(void)std::initializer_list<int>{(f(std::forward<Args>(args)), void(), 0)...};


btw можно еще подискутировать как это называется тут — http://stackoverflow.com/questions/28887549/how-to-call-the-idiom-of-using-an-array-to-apply-a-function-to-a-variadic-pack
In Zen We Trust
Отредактировано 06.03.2015 12:42 Abyx . Предыдущая версия .
Re[5]: хитрая конструкция
От: Nikе Россия  
Дата: 06.03.15 12:44
Оценка:
Здравствуйте, niXman, Вы писали:

X>так вы об этом)

X>это нормально, и прописано в стандарте.

Как бы да. Просто сначала появилась версия, что такая форма как-то позволяет специфицировать порядок вызовов. Иначе совсем непонятно — зачем она нужна.
Нужно разобрать угил.
Re[6]: хитрая конструкция
От: niXman Ниоткуда https://github.com/niXman
Дата: 06.03.15 12:46
Оценка:
Здравствуйте, Nikе, Вы писали:

N>Иначе совсем непонятно — зачем она нужна.

да, использование лямбды тут совершенно необосновано.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[7]: хитрая конструкция
От: Hard_Club  
Дата: 06.03.15 13:28
Оценка:
X>да, использование лямбды тут совершенно необосновано.

а как можно без лямбды?
Re[8]: хитрая конструкция
От: Кодт Россия  
Дата: 06.03.15 15:14
Оценка: 25 (2)
Здравствуйте, Hard_Club, Вы писали:

X>>да, использование лямбды тут совершенно необосновано.


H_C>а как можно без лямбды?


Да любым способом утилизировать произвольное количество аргументов.
void devnull(...) {}

#define CALL(expr) ( (expr), void(), 0 ) // выполняет выражение, возможно, типа void, и возвращает int 0

template<class F, class... Xs>
void each(F f, Xs&&... xs)
{
  devnull( CALL(f(xs))... );
  (void) std::initializer_list<int> { CALL(f(xs))... };
  int nulls[] = { CALL(f(xs))... };

}
Перекуём баги на фичи!
Отредактировано 06.03.2015 15:15 Кодт . Предыдущая версия .
Re[9]: хитрая конструкция
От: Hard_Club  
Дата: 06.03.15 17:54
Оценка:
К>void devnull(...) {}

К>#define CALL(expr) ( (expr), void(), 0 ) // выполняет выражение, возможно, типа void, и возвращает int 0


К>template<class F, class... Xs>

К>void each(F f, Xs&&... xs)
К>{
К> devnull( CALL(f(xs))... );
К> (void) std::initializer_list<int> { CALL(f(xs))... };
К> int nulls[] = { CALL(f(xs))... };

К>}

К>[/c]

Как эта штука — #define CALL(expr) ( (expr), void(), 0 ) — называется в стандарте?
Re[10]: хитрая конструкция
От: Кодт Россия  
Дата: 06.03.15 19:21
Оценка:
Здравствуйте, Hard_Club, Вы писали:

H_C>Как эта штука — #define CALL(expr) ( (expr), void(), 0 ) — называется в стандарте?


Comma operator
Неявно определён над любыми (в т.ч. void) операндами, строго последовательно выполняет их и возвращает значение правого операнда.
Здесь получается такая конструкция
#define COMMA(x,y) ((x),(y))
#define CALL(expr) COMMA( COMMA((expr),void()), 0 )

Первая запятая над expr и void нужна для того, чтобы предотвратить нечаянный выбор перегруженного оператора запятой. (Перегрузить оператор для void-аргумента в принципе невозможно).
Результат имеет тип void, а уже void,int — заведомо — неявно определён компилятором.

Подытоживая,
— f(x) — может быть void или какого-нибудь неудобного для передачи в (...) типа
— f(x),0 — может быть типа с перегруженным operator,(T,int) — получим вместо int неизвестно что
— f(x),void() — получим void, но ничего с ним не сможем сделать
— f(x),void(),0 — получим int
Перекуём баги на фичи!
Отредактировано 07.03.2015 11:23 Кодт . Предыдущая версия .
Re[11]: хитрая конструкция
От: Hard_Club  
Дата: 07.03.15 14:59
Оценка:
К>Подытоживая,
К>- f(x) — может быть void или какого-нибудь неудобного для передачи в (...) типа
К>- f(x),0 — может быть типа с перегруженным operator,(T,int) — получим вместо int неизвестно что
К>- f(x),void() — получим void, но ничего с ним не сможем сделать
К>- f(x),void(),0 — получим int

а что в данном случае void() со скобками
Re[12]: хитрая конструкция
От: Кодт Россия  
Дата: 07.03.15 16:57
Оценка:
Здравствуйте, Hard_Club, Вы писали:

H_C>а что в данном случае void() со скобками


Конструктор значения типа void %)
Ещё встречается чуть менее лаконичное (void)0
Перекуём баги на фичи!
Re[13]: хитрая конструкция
От: uzhas Ниоткуда  
Дата: 07.03.15 17:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Конструктор значения типа void %)

К>Ещё встречается чуть менее лаконичное (void)0

void — это какой-то хак в системе типизации, причем явно перегруженный смыслом
с одной стороны, это неполный "тип" и у него не может быть экземляров, а с другой стороны это и не тип вообще

вот тут можно немного почитать об этом
http://stackoverflow.com/questions/1043034/what-does-void-mean-in-c-c-and-c
Re[13]: хитрая конструкция
От: niXman Ниоткуда https://github.com/niXman
Дата: 07.03.15 18:39
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ещё встречается чуть менее лаконичное (void)0

стОит отметить, что выражение типа:
int v = 0;
((void)v);

не означает, что v станет типом void. это просто "посыл" компилятору о том, что если v не используется, чтоб он не сообщал об этом.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[9]: хитрая конструкция
От: x-code  
Дата: 07.03.15 19:56
Оценка: -1
Здравствуйте, Кодт, Вы писали:

К>Да любым способом утилизировать произвольное количество аргументов.


Что-то эта тема (шаблоны с переменным числом аргументов) как-то вообще мимо меня прошла
Вы можете рассказать хоть что-то поподробнее, как оно вообще работает?
Как такие шаблоны разворачиваются в компиляторе?
Какие есть вообще способы с ними работать?
Re[10]: хитрая конструкция
От: Abyx Россия  
Дата: 07.03.15 20:47
Оценка: +2 -4
Здравствуйте, x-code, Вы писали:

XC>Что-то эта тема (шаблоны с переменным числом аргументов) как-то вообще мимо меня прошла

XC>Вы можете рассказать хоть что-то поподробнее, как оно вообще работает?
XC>Как такие шаблоны разворачиваются в компиляторе?
XC>Какие есть вообще способы с ними работать?

и тебя в гугле забанили? попробуй тогда какой-нибудь яндекс или поиск мейл.ру
In Zen We Trust
Re[10]: хитрая конструкция
От: Кодт Россия  
Дата: 07.03.15 21:26
Оценка: 16 (4)
Здравствуйте, x-code, Вы писали:

XC>Что-то эта тема (шаблоны с переменным числом аргументов) как-то вообще мимо меня прошла

XC>Вы можете рассказать хоть что-то поподробнее, как оно вообще работает?
XC>Как такие шаблоны разворачиваются в компиляторе?
XC>Какие есть вообще способы с ними работать?

Как разворачиваются: берётся серия аргументов (параметров шаблона, аргументов функции) и подставляется одним махом.
template<bla,bla,bla> struct Foo; // не обязательно вариадик, а просто много-много-арный шаблон

void foo(bla,bla,bla); // то же самое - там могут быть и дефолтные параметры, и сишный эллипсис,
void foo(); // и перегрузки, и что угодно


template<class... Args> void bar(Args... args) // если параметры шаблона не указаны, они довыводятся из аргументов
{
  Foo<Args...> x; // подставили параметры шаблона - здесь типы - в параметры другого шаблона.
  foo(args...); // подставили серию аргументов
  sizeof...(Args); // число параметров шаблона
  sizeof...(args); // число аргументов функции

  int   xs[] = { f<Args>()... }; // подставили каждый элемент Args в выражение - например, в шаблон функции
  void* ys[] = { new Args()... }; // необязательно в шаблон - типы можно использовать как угодно
  int   zs[] = { f(args)... }; // подставили каждый элемент args
}


Ну и всякие операции над сериями параметров шаблонов возможны. Например, сопоставление (с началом серии).
В общем, метапрограммирование во всей красе. Раньше был лисп, а теперь чуть-чуть не дотянули до рефала.
template<class... Args> struct mpl_series {};

// можно делать сопоставление глубоко

template<class> struct mpl_front;
template<class X, class... Args> struct mpl_front< mpl_series<X,Args...> > { typedef X type; };

// а можно и непосредственно

template<class... Args> struct mpl_sizeof;
template<> struct mpl_sizeof<> {
  static int const value = 1;
};
template<class X, class... Rest> struct mpl_sizeof<X,Rest...> {
  static int const value = 1 + mpl_sizeof<Rest...>::value;
};

// единственно, склеивать две последовательности напрямую не выйдет, хотя бы одна должна быть упакована

template<class Series, class...> struct mpl_append;
template<class... Xs, class... Ys> struct mpl_append< mpl_series<Xs...>, Ys... >
 { typedef mpl_series<Xs...,Ys...> type; };

template<class Series1, class Series2> struct mpl_concat;
template<class... Xs, class... Ys> struct mpl_concat< mpl_series<Xs...>, mpl_series<Ys...> >
 { typedef mpl_series<Xs...,Ys...> type; };

// и, с хвостом серии нельзя напрямую сопоставляться, хвост можно только порождать

template<class Series> struct mpl_rotate;
template<class X, class...Ys> struct mpl_rotate< mpl_series<X,Ys...> >
 { typedef mpl_series<Ys...,X> };
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.