Изучаем С++17
От: Шахтер Интернет  
Дата: 06.05.16 18:05
Оценка:
Создание многоаргументных функций.


template <class T> concept bool AnyType = true ;

template <AnyType T,T Add(T,T)>
struct OpAddHelper
 {
  T val;

  OpAddHelper(AnyType arg) : val(arg) {}

  OpAddHelper operator + (OpAddHelper obj) const { return Add(val,obj.val); }
 };

ulen Add(ulen a,ulen b)
 {
  if( a>MaxULen-b ) GuardLenAddOverflow(a,b);

  return a+b;
 }

ulen Func(AnyType ... args)
 {
  return ( ... + OpAddHelper<ulen,Add>(args) ).val;
 }

template <AnyType T>
T Max(T a,T b) { return (a<b)?b:a; }

template <AnyType T>
T Max_auto(T a,AnyType ... args)
 {
  return ( OpAddHelper<T,Max>(a) + ... + OpAddHelper<T,Max>(args) ).val;
 }

Func(1,2,3u)

Max_auto(1,2,3u)
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Изучаем С++17
От: Кодт Россия  
Дата: 11.05.16 17:31
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Создание многоаргументных функций.


Возможны варианты:
#include <iostream>
using namespace std;

// уникально именованая пара
template<class F, class A> struct and_more { F f; A a; };
template<class F, class A> auto make_and_more(F f, A a) { return and_more<F,A>{f, a}; }

template<class X, class F, class Y>
static auto operator > (X x, and_more<F,Y> fy) { return fy.f(x, fy.a); }

template<class F, class X, class... Ys>
auto fold_left(F f, X x, Ys... ys) { return (x > ... > make_and_more(f, ys)); }


template<class X, class F, class Y>
static auto operator < (and_more<F,X> fx, Y y) { return make_and_more(fx.f, fx.f(fx.a, y)); }

template<class F, class X, class... Ys>
auto fold_left_v2(F f, X x, Ys... ys) { return (make_and_more(f, x) < ... < ys).a; }

// тестируем!

// полиморфная функция
struct verbose_second {
  template<class X, class Y>
  auto operator()(X x, Y y) const {
    cout << __PRETTY_FUNCTION__ << "(" << x << "," << y << ") = " << y << endl;
    return y;
  }
};

struct verbose_plus {
  template<class X, class Y>
  auto operator()(X x, Y y) const {
    cout << __PRETTY_FUNCTION__ << "(" << x << "," << y << ") = " << y << endl;
    return x + y;
  }
};
 
int main() {
  auto z = fold_left(verbose_second(), '1', 2, 3u, "4?!");
  cout << z << endl;
  auto z2 = fold_left_v2(verbose_second(), '1', 2, 3u, "4?!");
  cout << z2 << endl;
  auto t = fold_left(verbose_plus(), char(1), char(2), 3U, 4L, 5UL, 6.f, 7., 8);
  cout << t << endl;
}


fold_left сразу создаёт все пары (функция,операнд), затем сворачивает их.
fold_left_v2 — создаёт пары (функция,результат).
Что лучше, это ещё вопрос. По идее, вся эта куча пар должна дожить до конца полного выражения.
И я бы предпочёл именно первый вариант, т.к. он позволяет держать ссылки на операнды, тогда как второй безусловно должен держать значения.

Кстати, вопрос. Как бесплатно сделать fold_right?
Замена на правоассоциативный оператор ничего не даёт: коварный вариадик всё равно разворачивается левоассоциативно.
Перекуём баги на фичи!
Re[2]: Изучаем С++17
От: Шахтер Интернет  
Дата: 11.05.16 17:45
Оценка: 36 (1) +1
Здравствуйте, Кодт, Вы писали:

К>Кстати, вопрос. Как бесплатно сделать fold_right?

К>Замена на правоассоциативный оператор ничего не даёт: коварный вариадик всё равно разворачивается левоассоциативно.

Всё просто.

( ... + AA ) -- ( a + b ) + c
( AA + ... ) -- a + ( b + c )

От оператора не зависит.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Изучаем С++17
От: -MyXa- Россия  
Дата: 11.05.16 18:47
Оценка:
Здравствуйте, Шахтер, Вы писали:

А ну если мы так?
Max_auto(1,2,3u,MaxULen)
Если не поможет, будем действовать током... 600 Вольт (C)
Re: Изучаем С++17
От: Vain Россия google.ru
Дата: 11.05.16 21:55
Оценка: +6
Здравствуйте, Шахтер, Вы писали:

Ш>Создание многоаргументных функций.

в глазах рябит
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[3]: Изучаем С++17
От: Кодт Россия  
Дата: 12.05.16 00:48
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Всё просто.


Ш>( ... + AA ) -- ( a + b ) + c

Ш>( AA + ... ) -- a + ( b + c )

Ш>От оператора не зависит.


А для пустого списка что получится?

С foldl всё просто, вводим стартовое значение
(x0 + ... + ys) = (((x0+y1) + y2) + y3)

С foldr — мы не сможем сматчить аргументы: вариадик должен быть последним.
template<class F, class... Xs, class Y>
auto foldr(F f, Xs... xs, Y y) // объявить-то можем, а использовать - нет.
{
  return (xs + ... + operand(f,y));
}


Выход, разве что, в создании нейтрального элемента — и перегрузки оператора для него.
struct N {};

template<class F, class A> struct operand { F f; A a; };
template<class F, class A> auto make_operand(F f, A a) { return operand<F,A>{f,a}; }

template<class F, class A, class Y> auto operator < (operand<F,A> x, Y y) { return make_operand(x.f, x.f(x.a, y)); }

template<class X, class F, class A> auto operator > (X x, operand<F,A> y) { return make_operand(y.f, y.f(x, y.a)); }
template<class X, class F> auto operator > (X x, operand<F,N> y) { return make_operand(y.f, x); }

template<class F, class X, class... Xs> auto foldl(F f, X x, Xs... xs) { return (make_operand(f,x) < ... < xs).a; }
template<class F, class X, class... Xs> auto foldr(F f, X x, Xs... xs) { return (x > (xs > ... > make_operand(f,N()))).a; }
Перекуём баги на фичи!
Re[4]: Изучаем С++17
От: Шахтер Интернет  
Дата: 12.05.16 18:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Шахтер, Вы писали:


Ш>>Всё просто.


Ш>>( ... + AA ) -- ( a + b ) + c

Ш>>( AA + ... ) -- a + ( b + c )

Ш>>От оператора не зависит.


К>А для пустого списка что получится?


В этих двух вариантах список должен быть непустой.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Изучаем С++17
От: Кодт Россия  
Дата: 12.05.16 23:23
Оценка:
Здравствуйте, Шахтер, Вы писали:

К>>А для пустого списка что получится?

Ш>В этих двух вариантах список должен быть непустой.

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

Но тут есть два минуса.

Первый: проверка валидности проваливается внутрь функции. Вместо ошибки сопоставления получаем ошибку компиляции. Хотим управлять сопоставлением — должны прикладывать нетривиальные усилия, старое доброе sfinae или перегрузки руками расписывать.
Для левой свёртки таких проблем нет: foldl(f,x0,xs...)
Для правой — либо пишем навыворот: foldr(f,xn,xs...), либо что-то типа foldr(f,xs...)->enable_if(sizeof...(xs)>0)

Второй: принудительно однородная свёртка. Аккумулятор вынужден быть того же вида, что и все остальные операнды.
Применительно к нашему трюку, когда мы операнды склеиваем с функцией, — для неоднородной свёртки надо сделать N-1 проекций, по числу операторов, а для однородной — N, то есть, один раз лишний.

Хотя, впрочем, отделять аккумулятор от списка — это правильный подход, Шейнфинкель с Карри одобрили бы: foldl(f,x0)(xs...) и foldr(f,xn)(xs...)
namespace aux {
  template<class F, class X> struct seed_t { F f; X x; };
  template<class F, class X> auto lift(F f, X x) { return seed_t<F,X>{f,x}; }
  template<class F, class X> auto land(seed_t<F,X> fx) { return fx.x; }
  template<class F, class X, class A, class B> auto play(seed_t<F,X> fx, A a, B b) { return lift(fx.f, fx.f(a,b)); }
  template<class Y, class F, class X> auto operator + (Y y, seed_t<F,X> fx) { return play(fx, y, land(fx)); }
  template<class Y, class F, class X> auto operator + (seed_t<F,X> fx, Y y) { return play(fx, land(fx), y); }
}

template<class F, class X> struct fold_t {
  F f; X x;
  template<class... Ys> auto left (Ys... ys) const { return aux::land((aux::lift(f,x) + ... + ys)); }
  template<class... Ys> auto right(Ys... ys) const { return aux::land((ys + ... + aux::lift(f,x))); }
};
template<class F, class X> auto fold(F f, X x) { return fold_t<F,X>{f,x}; }

int main() {
  cout << fold( [](auto x, auto y) { return x*10 + y; }, 0 ).left (1, 2, 3, 4) << endl; // 0*10+1, 1*10+2, 12*10+3, 123*10+4 = 1234
  cout << fold( [](auto x, auto y) { return x + y*10; }, 0 ).right(1, 2, 3, 4) << endl; // 4+0*10, 3+4*10, 2+43*10, 1+432*10 = 4321
}
Перекуём баги на фичи!
Re[2]: Изучаем С++17
От: Кодт Россия  
Дата: 13.05.16 11:10
Оценка:
Здравствуйте, Vain, Вы писали:

V>в глазах рябит


Ну, тут можно подискутировать, что более рябит, а что менее: хакнуть двухместный оператор (поиграть в аппликативные функторы) и затем воспользоваться свёрткой, или написать рекурсию вручную.
template<class F, class X>
auto foldl(F f, X x) { return x; }

template<class F, class X, class Y, class... Zs>
auto foldl(F f, X x, Y y, Zs... zs) { return foldl(f, f(x,y), zs...); }

////////

template<class F, class X>
auto foldr(F f, X x) { return x; }

template<class F, class X, class... Zs>
auto foldr(F f, X x, Zs... zs) { return f(x, foldr(f, zs...)); }
Перекуём баги на фичи!
Re[3]: Изучаем С++17
От: uzhas Ниоткуда  
Дата: 13.05.16 11:12
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ну, тут можно подискутировать, что более рябит


в первую очередь рябит вырвиглазный стиль ТС
Re[4]: Изучаем С++17
От: Шахтер Интернет  
Дата: 14.05.16 01:25
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Кодт, Вы писали:


К>>Ну, тут можно подискутировать, что более рябит


U>в первую очередь рябит вырвиглазный стиль ТС


Моим глазам нравится
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Изучаем С++17
От: uzhas Ниоткуда  
Дата: 14.05.16 16:42
Оценка: -1 :)
Здравствуйте, Шахтер, Вы писали:

U>>в первую очередь рябит вырвиглазный стиль ТС


Ш>Моим глазам нравится


в эТОм Ни_кТо нЕ соМНЕвАЕТся (:
Re[4]: Изучаем С++17
От: Temnikov Россия  
Дата: 17.05.16 11:51
Оценка:
U>в первую очередь рябит вырвиглазный стиль ТС
"Верблюжий" регистр/стиль. В целом ничего плохого. Хуже когда несколько стилей мешают в кучу.

По теме, мне так не совсем понятно с практической точки зрения что с этим делать?
Ну и из-за поддержки всех этих "костылей" потом в продакшене, я не люблю применение шаблонов без необходимости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.