Здравствуйте, niXman, Вы писали:
X>так вы об этом) X>это нормально, и прописано в стандарте.
Как бы да. Просто сначала появилась версия, что такая форма как-то позволяет специфицировать порядок вызовов. Иначе совсем непонятно — зачем она нужна.
Здравствуйте, Hard_Club, Вы писали:
H_C>Как эта штука — #define CALL(expr) ( (expr), void(), 0 ) — называется в стандарте?
Comma operator
Неявно определён над любыми (в т.ч. void) операндами, строго последовательно выполняет их и возвращает значение правого операнда.
Здесь получается такая конструкция
Первая запятая над 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
К>Подытоживая, К>- f(x) — может быть void или какого-нибудь неудобного для передачи в (...) типа К>- f(x),0 — может быть типа с перегруженным operator,(T,int) — получим вместо int неизвестно что К>- f(x),void() — получим void, но ничего с ним не сможем сделать К>- f(x),void(),0 — получим int
Здравствуйте, Кодт, Вы писали:
К>Конструктор значения типа void %) К>Ещё встречается чуть менее лаконичное (void)0
void — это какой-то хак в системе типизации, причем явно перегруженный смыслом
с одной стороны, это неполный "тип" и у него не может быть экземляров, а с другой стороны это и не тип вообще
Здравствуйте, Кодт, Вы писали:
К>Да любым способом утилизировать произвольное количество аргументов.
Что-то эта тема (шаблоны с переменным числом аргументов) как-то вообще мимо меня прошла
Вы можете рассказать хоть что-то поподробнее, как оно вообще работает?
Как такие шаблоны разворачиваются в компиляторе?
Какие есть вообще способы с ними работать?
Здравствуйте, x-code, Вы писали:
XC>Что-то эта тема (шаблоны с переменным числом аргументов) как-то вообще мимо меня прошла XC>Вы можете рассказать хоть что-то поподробнее, как оно вообще работает? XC>Как такие шаблоны разворачиваются в компиляторе? XC>Какие есть вообще способы с ними работать?
и тебя в гугле забанили? попробуй тогда какой-нибудь яндекс или поиск мейл.ру
Здравствуйте, 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> };