не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 13:16
Оценка:
сабж...

я совсем потерянный С++'ник ?
Re: не могу читать трехэтажные шаблоны
От: Kswapd Россия  
Дата: 28.12.12 13:29
Оценка:
J>я совсем потерянный С++'ник ?

typedef не спасёт?
Re[2]: не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 13:51
Оценка:
Здравствуйте, Kswapd, Вы писали:

K>typedef не спасёт?


я об этом

struct PolymorphicFunctionObject
{
    template<typename T> struct result;

    template<typename Arg>
    struct result< PolymorphicFunctionObject(Arg) >
    {
        typedef Arg type;
    };

    template<typename Arg1,typename Arg2>
    struct result< PolymorphicFunctionObject(Arg1,Arg2) >
    {
        typedef Arg2 type;
    };

    template<typename Arg>
    Arg operator()(Arg t) const
    {
        return t;
    }

    template<typename Arg1,typename Arg2>
    Arg2 operator()(Arg1 t1,Arg2 t2) const
    {
        return t2;
    }
};
Re[3]: не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 13:53
Оценка:
я смотрю на такие конструкции как баран на новые ворота...
Re[4]: не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 13:55
Оценка:
я в отчаянии...
Re: не могу читать трехэтажные шаблоны
От: Evgeny.Panasyuk Россия  
Дата: 28.12.12 13:56
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>сабж...

J>я совсем потерянный С++'ник ?

Смысла "читать трехэтажные шаблоны" не понимая как работает перегрузка, ADL
Автор: jyuyjiyuijyu
Дата: 18.12.12
— нет.
Поэтому C++ Templates: The Complete Guide
Автор: jyuyjiyuijyu
Дата: 27.12.12
лучше отложить.
Если какие-то начальные представления о C++ есть — то советую сначала прочитать The C++ Programming Language Страуструпа, если же нет то тогда Programming Principles and Practice Using C++.
Re[2]: не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 14:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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


J>>сабж...

J>>я совсем потерянный С++'ник ?

EP>Смысла "читать трехэтажные шаблоны" не понимая как работает перегрузка, ADL
Автор: jyuyjiyuijyu
Дата: 18.12.12
— нет.

EP>Поэтому C++ Templates: The Complete Guide
Автор: jyuyjiyuijyu
Дата: 27.12.12
лучше отложить.

EP>Если какие-то начальные представления о C++ есть — то советую сначала прочитать The C++ Programming Language Страуструпа, если же нет то тогда Programming Principles and Practice Using C++.

ну как бы у меня знания далеко за начальными... но шаблоны мне как то недаются..
Re[3]: не могу читать трехэтажные шаблоны
От: jazzer Россия Skype: enerjazzer
Дата: 28.12.12 16:16
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

для этого надо понимать протокол resultof. Ну и там два шаблона, на самом деле.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: не могу читать трехэтажные шаблоны
От: include2h  
Дата: 28.12.12 16:18
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Смысла "читать трехэтажные шаблоны" не понимая как работает перегрузка, ADL
Автор: jyuyjiyuijyu
Дата: 18.12.12
— нет.

EP>Поэтому C++ Templates: The Complete Guide
Автор: jyuyjiyuijyu
Дата: 27.12.12
лучше отложить.

EP>Если какие-то начальные представления о C++ есть — то советую сначала прочитать The C++ Programming Language Страуструпа, если же нет то тогда Programming Principles and Practice Using C++.

О да, я эту навернутую конструкцию тоже не понял. Обхожусь как-то без таких наворотов. Кстати, может прокомментируете построчно зачем она нужна такая?
Нормальные шаблоны — это в моем понимании например такое
 template<class T, int N>
 class Array {
 T data[N];
 public:
 T& operator[](int i);
 };

ну может в реальных проектах методов будет побольше, но все равно идея понятна. Все конкретно. А вот что делает полезного абстрактная конструкция, приведенная топикстартером — ума не приложу.
Re[3]: не могу читать трехэтажные шаблоны
От: flаt  
Дата: 28.12.12 16:34
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>ну как бы у меня знания далеко за начальными... но шаблоны мне как то недаются..

Вспомни: поначалу сам язык кажется магией — все эти приоритеты операций, отличия между указателями, ссылками, уж не говоря про конструкции вида ->*
Потом это [ос|ус]ваивается, но теперь уже смотрим на шаблоны, которые, кроме простейших "template<typename T> T add(T x, T y)", также выызвают непонимание, а уж что говорить про труд Александреску, который кажется вообще за гранью фантастики.
Дальше — больше: буст, лямбды, && и std::forward, etc...
Re[3]: не могу читать трехэтажные шаблоны
От: Evgeny.Panasyuk Россия  
Дата: 28.12.12 17:08
Оценка: 4 (1)
Здравствуйте, include2h, Вы писали:

I>О да, я эту навернутую конструкцию тоже не понял. Обхожусь как-то без таких наворотов.


Людям и C и Pascal хватало Такую blub риторику — в топку.

I>Кстати, может прокомментируете построчно зачем она нужна такая?


Пожалуйста, здесь всё подробно расписал.

I>Нормальные шаблоны — это в моем понимании например такое

I>
 template<class T, int N>
I> class Array {
I> T data[N];
I> public:
I> T& operator[](int i);
I> };

I> ну может в реальных проектах методов будет побольше, но все равно идея понятна. Все конкретно. А вот что делает полезного абстрактная конструкция, приведенная топикстартером — ума не приложу.

Например есть структура, нужно сделать массив этих структур, причём известно что паттерны использования такие, что использование структуры массивов было бы выгоднее. Один из вариантов решения — Boost.Fusion + подобные конструкции.
Использовать или нет такие конструкции, естественно зависит от ситуации в конкретном проекте
Re[3]: не могу читать трехэтажные шаблоны
От: Evgeny.Panasyuk Россия  
Дата: 28.12.12 17:21
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

EP>>Смысла "читать трехэтажные шаблоны" <b>не понимая как работает перегрузка, ADL</b>
Автор: jyuyjiyuijyu
Дата: 18.12.12
— нет.

J>ну как бы у меня знания далеко за начальными... но шаблоны мне как то недаются..

ОК.
Есть namespace math, в нём обычный класс dcomplex. Куда поместить функцию cos?
ответ
Автор: jyuyjiyuijyu
Дата: 18.12.12
:

ну math::dcomplex::cos как то логичней меньше конфликтов возможных...

Каких конфликтов? Что насчёт ADL? Что с удобством?
Re[4]: не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 18:08
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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


EP>>>Смысла "читать трехэтажные шаблоны" <b>не понимая как работает перегрузка, ADL</b>
Автор: jyuyjiyuijyu
Дата: 18.12.12
— нет.

J>>ну как бы у меня знания далеко за начальными... но шаблоны мне как то недаются..

EP>ОК.

EP>Есть namespace math, в нём обычный класс dcomplex. Куда поместить функцию cos?
EP>ответ
Автор: jyuyjiyuijyu
Дата: 18.12.12
:

EP>

EP>ну math::dcomplex::cos как то логичней меньше конфликтов возможных...

EP>Каких конфликтов? Что насчёт ADL? Что с удобством?


ну например сущностей с такими же именами с ADL я плохо знаком с удобством для нешаблонных классов все в порядке
Re[3]: не могу читать трехэтажные шаблоны
От: Кодт Россия  
Дата: 28.12.12 19:29
Оценка: 45 (4)
Здравствуйте, jyuyjiyuijyu, Вы писали:

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

J>я об этом

  Скрытый текст
J>
J>struct PolymorphicFunctionObject
J>{
J>    template<typename T> struct result;

J>    template<typename Arg>
J>    struct result< PolymorphicFunctionObject(Arg) >
J>    {
J>        typedef Arg type;
J>    };

J>    template<typename Arg1,typename Arg2>
J>    struct result< PolymorphicFunctionObject(Arg1,Arg2) >
J>    {
J>        typedef Arg2 type;
J>    };

J>    template<typename Arg>
J>    Arg operator()(Arg t) const
J>    {
J>        return t;
J>    }

J>    template<typename Arg1,typename Arg2>
J>    Arg2 operator()(Arg1 t1,Arg2 t2) const
J>    {
J>        return t2;
J>    }
J>};
J>


Если ты конкретно об этом, то давай попробуем вместе разобраться.

Первое. ЧТО эта конструкция делает?
Ответ очевиден: здесь определены две функции — Arg pfo(Arg) и Arg2 pfo(Arg1,Arg2), где Arg1, Arg2 — произвольные типы.
(Далее, для краткости, я буду называть их pfo, а не PolymorphicFunctionObject).

Второе. Зачем обе они засунуты в один класс?
Это такая идиома: засовывать семейство функций, то есть нечто полиморфное, в класс фиксированного типа.
Семейство может строиться как шаблон функций, как набор перегрузок, или — как здесь — и перегрузка, и шаблоны.
Эта идиома позволяет передавать всё семейство функций как аргумент вызова или как параметр шаблона.
Дело в том, что семейство обычных функций (шаблонных или нет) идентифицируется по имени, а имя как таковое не является первоклассной сущностью. То есть, сказать компилятору имя мы можем и должны, а вот передать и сохранить имя — уже никак. Только указатели или абстрагированные типы — параметры шаблона. В С++ рефлексия никакая.
А тут очень удобно: завернули семейство в тип, и можем передавать и сам тип как параметр шаблона, и его экземпляры как аргументы функций.

Третье. Надеюсь, не надо объяснять, как класс с оператором() синтаксически выглядит, словно функция?

А вот четвёртое — это существенное отличие.
Допустим, мы хотим написать
auto x = pfo(y,z);
// или даже круче
typedef typeof(pfo(y,z)) X;
X x1, x2; .....

хорошо компилятору, если он, во-первых, поддерживает стандарт C++11 (или, хотя бы, расширения gcc-03). Конечно, даже C++98 компилятор сможет вывести тип результата pfo(y,z) для известных y и z, но пользователю он ничего не позволит с этим выводом сделать.
А потребность узнать тип результата часто встречается. Например, от неё может зависеть тип функции, в которой, собственно, и был сделан вызов pfo.

Для обычных функций можно выполнить разбор типа:
template<class R, class A1, class A2>
shared_ptr<R> // чисто для примера - пусть foo возвращает некоторый тип, производный от искомого
foo( R(*f)(A1,A2) ) // здесь мы выполняем сопоставление
{
  return shared_ptr<R>(new f(0,0));
}

// там, где сопоставлять вот так неудобно, можем написать единожды метафункцию
template<class F> struct bin_fun_traits;
template<class R, class A1, class A2> struct bin_fun_traits< R(A1,A2) >
{
  typedef A1 a1_type;
  typedef A2 a2_type;
  typedef R  result_type;
};

template<class F> struct Foo // ну можно, конечно, написать struct Foo<R(A1,A2)>... 
{
  typedef typename bin_fun_traits<F>::result_type res_type;
  typedef shared_ptr<res_type> ptr_type;
  ptr_type p_, q_;
  .....
  void setup(Foo f)
  {
    p_ = ptr_type(new f(1,2));
    q_ = ptr_type(new f(3,4));
  }
  .....
};


Для произвольных классов, выдающих себя за функции, — понятное дело, такое сопоставление ничего не даст.
Поэтому разработчики договариваются передавать вместе с классом сопроводительную информацию.

Первая такая конвенция возникла в эпоху достандарта 98 года, первые версии STL. Тогдашние компиляторы были очень глупыми, и приходилось писать
struct multiply
{
  typedef int first_argument_type;
  typedef int second_argument_type;
  typedef int result_type;
  int operator()(int x, int y) const { return x*y; }
};

или, что проще, наследоваться от заготовок — std::unary_function<A1,R> и std::binary_function<A1,A2,R>.

Вторая конвенция — когда появился boost::bind, способный принимать всеядные функции — но тип результата ему всё ещё нужен.
struct whatever_less
{
  typedef bool type;
  template<class X, class Y> bool operator()(X x, Y y) const { return x<y; }
};

boost::function<bool(char)> is_ctrl = boost::bind(whatever_less, _1, 32); // слишком простой пример, но наворачивать что-то реальное я не хочу


Но понятно, что если в класс завёрнуто семейство функций, возвращающих разные типы, то такой фокус не пройдёт.
И вот тогда — внимание, трюк! Даже два трюка!

Напишем метафункцию, которая по набору типов аргументов выдаст искомый тип результата. И засунем эту метафункцию в наш класс.
struct tararam
{
  // вот наши функции
  int operator()(int x, int y) const { return x-y; }
  short operator()(char x, char y) const { return (short)(x+y); }

  // а вот метафункция, описывающая их
  template<class X, class Y> struct result;
  template<> struct result<int,int>   { typedef int type; };
  template<> struct result<char,char> { typedef short type; };
};

template<class F, class X> void foo(F f, X x, X y)
{
  typedef typename F::template result<X,X>::type xx_type;
  shared_ptr<xx_type> r (new f(x,y));
  .....
}
...
foo(tararam, 'a', 'b');


Хорошо получилось? Почти. Ведь, если у семейства функций разная арность (количество аргументов), то придётся писать семейство метафункций?
struct tararam
{
  // вот наши функции
  int operator()(int x) const { return -x; }
  short operator()(char x, char y) const { return (short)(x+y); }

  // а вот метафункция, описывающая их
  template<class X> struct result1;
  template<> struct result1<int> { typedef int type; };

  template<class X, class Y> struct result2;
  template<> struct result2<char,char> { typedef short type; };
};


Так можно, но некрасиво. Тут придётся или прибегнуть к variadic templates (шаблонам с произвольным количеством параметров), или как-то упаковывать параметры в один синтетический тип, поддающийся сопоставлению.
Вариадики
template<Args...> struct result;
template<> struct result<int> { ..... };
template<> struct result<char,char> { ..... };

Синтетические типы в C++ есть. Самых популярных — три штуки: boost::tuple, boost::mpl::vector и, о чудо, сигнатура функции.
template<class Tuple> struct result;
template<> struct result< tuple<int> > { ..... };
template<> struct result< tuple<char,char> > { ..... };

.....
typedef typename F::template result< tuple<X,X> >::type xx_type;

////////////////

template<class Fun> struct result;
template<> struct result< tararam(int) > { ..... };
template<> struct result< tararam(char,char) > { ..... };

.....
typedef typename F::template result< F(X,X) >::type xx_type;

Последнее выгодно тем, что
— не тащит лишних зависимостей (от boost/std::tuple или boost::mpl)
— выглядит соответственно вызову: F(X,X) и f(x,x)


Кстати, заметь!
В моих отрывках — сперва идут сами функции, а потом их обвязка метафункцией. Как мне кажется, это упрощает понимание, ставит лошадь впереди телеги.
А в твоём примере телега впереди, и это, конечно, слегка озадачивает: откуда взялась эта метафункция, зачем она вообще?
Но это уже вопросы стиля. Точно так же, как некоторые любят писать private-секцию с членами-данными в начале класса (чтобы был виден его лэяут), а другие — в конце (выставляя на первое место его public интерфейс).

Возможно, что и некоторые другие "трёхэтажные" конструкции станет легче понимать, если мысленно выделять и переставлять смысловые блоки.
Перекуём баги на фичи!
Re[4]: не могу читать трехэтажные шаблоны
От: jyuyjiyuijyu  
Дата: 28.12.12 20:25
Оценка:
Здравствуйте, Кодт, Вы писали:

спасибо за объяснение

перечитал два раза
но видимо мой уровень в шаблонах настолько низок что я понимаю Вас с трудом
Re[5]: не могу читать трехэтажные шаблоны
От: Evgeny.Panasyuk Россия  
Дата: 28.12.12 20:52
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

EP>>Есть namespace math, в нём обычный класс dcomplex. Куда поместить функцию cos?

EP>>ответ
Автор: jyuyjiyuijyu
Дата: 18.12.12
:

EP>>

EP>>ну math::dcomplex::cos как то логичней меньше конфликтов возможных...

EP>>Каких конфликтов? Что насчёт ADL? Что с удобством?
J>ну например сущностей с такими же именами

Какая сигнатура должна быть и где должны быть расположены эти сущности, чтобы наступил конфликт?

J>с ADL я плохо знаком


Есть в TC++PL.

J>с удобством для нешаблонных классов все в порядке


Что удобней:
1. math::dcomplex::cos(value)
2. dcomplex::cos(value) // после using
3. cos(value) // даже без всяких using, при том что cos находится в math
?

У Страуструпа рассматриваются подобные и многие другие моменты. Но что самое главное, он учит хорошему стилю.
Начинать нужно именно с этого, а не с TMP.
Re[5]: не могу читать трехэтажные шаблоны
От: Кодт Россия  
Дата: 28.12.12 21:45
Оценка: 16 (2)
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>перечитал два раза

J>но видимо мой уровень в шаблонах настолько низок что я понимаю Вас с трудом

Могу повторить третий раз и помедленнее

Если коротко, то здесь есть идиомы:

1) запихнуть семейство функций в класс, — чтобы передавать это семейство в другие шаблоны (по имени можно передавать только в макросы, а макросы в сях, сам знаешь, насколько интеллектуальные)

2) чтобы узнать тип, возвращаемый функцией, — нужно или использовать фичи стандарта 2011 (decltype), или метафункцию: специальный шаблон, который по типу аргументов выводит тип результата.

3) чтобы передавать произвольное количество типов аргументов, — нужно или использовать фичи 2011 (вариадики), или упаковывать типы в кортеж.
В качестве кортежа взяли тип сигнатуры функции: doesnt_matter(arg1_type,arg2_type,arg3_type)

Подозреваю, что больше всего напрягает метафункция и её применение.
Ну тут да, есть немножко шаблонной магии
Очень советую прочитать Александреску, а потом забыть его поскорее. Там показано, как эту шаблонную магию готовят, но... в общем, не надо делать, как Александреску сделал в Loki.

Опять же, если вкратце.

Обычные шаблоны как работают? Ты пишешь основной шаблон template<class A, class B> class Foo и, по желанию, его частичные и полные специализации. Затем подсовываешь в угловые скобки нужные тебе параметры, компилятор ищет подходящую специализацию и дальше имеет дело с конкретным классом.

Первая хитрость: сопоставление аргументов может быть затейливым. Мы можем выковыривать базовые типы из производных
template<class> class WhatAboutPointer;
template<class T> class WhatAboutPointer<T*> { .... T .... };
.....
WhatAboutPointer<int*> // в этом классе параметр T принял значение int

template<class> class WhatAboutBinaryFunction;
template<class R, class X, class Y> class WhatAboutBinaryFunction< R(X,Y) > { .... R .... X .... Y .... };
.....
typedef int foo_signature(char,short);
WhatAboutBinaryFunction< foo_signature > // выделили из сигнатуры, что она получает и что возвращает


Вторая хитрость: специализации шаблонов — это аналоги перегрузки функций.
int foo(char);
long foo(char,short);
..... foo('a') ..... // вызовем первую сигнатуру, как наиболее подходящую

template<class> struct Foo;
template<class R, class X> struct Foo<R(X)> { ..... }; // первая специализация
template<class R, class X, class Y> struct Foo<R(X,Y)> { ..... }; // вторая
..... Foo<int(char)> ..... // класс получен из первой специализации шаблона


Третья хитрость: иногда нас интересуют объекты — экземпляры класса, полученного по шаблону. Со всеми их данными и методами. Собственно, это классическое применение шаблонов, и все учебники по С++ с этого и начинают.
Но иногда! Нам нужны так называемые зависимые имена — типы и константы, объявленные в шаблоне.
template<class T> struct AddPointer { typedef T* type; };
typedef typename AddPointer<int>::type pint; // pint - это int*

Шаблон класса, который эксплуатируют только ради зависимых имён, принято называть "характеристиками" (traits, трейтс).

Если ты спросишь, а нафига нужно typedef typename AddPointer<int>::type, если можно сразу написать int*, то отвечу.
  если ты спросишь; а так — не отвлекайся от хода мысли
1) иногда зависимые типы бывают довольно затейливыми
2) трейтс позволяет не только дописать что-то к параметру (из int сделать int*), но и что-то выдрать (из int* сделать int, например)
3) иногда нужно ввести абстрагирующую прослойку: сегодня и на этой платформе тип будет один, а завтра и на другой — поменяется (условная компиляция, версии программы)
4) при известной ловкости, мы можем подсовывать в один и тот же пользовательский шаблон разные трейтсы.


Четвёртая хитрость:
Трейтс — это аналог объекта. Только если у объекта есть члены-данные, то у трейтса — зависимые имена-типы.
Но, помимо объектов, есть ещё такое явление, как функция. У функции сколько-то аргументов, а возвращает она одно значение.
Поэтому довольно часто используется вырожденный случай трейтса: шаблон класса, который содержит одно только зависимое имя.
Эта штука называется метафункцией, и является аналогией функции.
int foo(int x) { return x+1; }

template<int X> struct F { static const value = X+1; }; // метафункция над числами
template<class T> struct P { typedef T* type; }; // метафункция над типами


Теперь собираем все четыре хитрости вместе

Как писать метафункции, и как применять их — это тема для отдельного разговора.
Но, по крайней мере, надеюсь, что ты станешь узнавать трейтсы и метафункции, и это не будет больше горой непонятных угловых скобочек, понапиханных неизвестно зачем.
Перекуём баги на фичи!
Re[5]: не могу читать трехэтажные шаблоны
От: alexeiz  
Дата: 29.12.12 04:19
Оценка: +1
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>перечитал два раза

J>но видимо мой уровень в шаблонах настолько низок что я понимаю Вас с трудом

Шаблоны (в смысле template metaprogramming) сходны с функциональным программированием. Поэтому тебе может помочь изучение какого-нибудь функционального языка.

Ну а так, чем больше пишешь кода с использованием шаблонов, тем лучше их понимание.
Re[6]: не могу читать трехэтажные шаблоны
От: uzhas Ниоткуда  
Дата: 29.12.12 18:14
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Шаблоны (в смысле template metaprogramming) сходны с функциональным программированием. Поэтому тебе может помочь изучение какого-нибудь функционального языка.


ссылка по теме: http://accu.org/index.php/journals/1422
Re[4]: не могу читать трехэтажные шаблоны
От: carpenter Голландия  
Дата: 29.12.12 20:20
Оценка:
Здравствуйте, Кодт, Вы писали:

ми пардоне, мне для понимания нужно знать, где и как это безобразие может\должно пользоваться?
можно вкратце ... спасибо.
Весь мир — Кремль, а люди в нем — агенты
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.