Трюки с fold expression
От: _NN_ www.nemerleweb.com
Дата: 27.05.20 14:58
Оценка: 48 (8) :))
Полезный набор
https://foonathan.net/2020/05/fold-tricks/

Например
for (auto elem : ts)
{
    if (pred(elem))
        return elem;
}


==>

std::common_type_t<decltype(ts)...> result;
bool found = ((pred(ts) ? (result = ts, true) : false) || ...);
// expands to: (pred(ts[0]) ? (result = ts[0], true) : false)
//          || (pred(ts[1]) ? (result = ts[1], true) : false)
//          || ...
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Трюки с fold expression
От: Mr.Delphist  
Дата: 08.06.20 12:30
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>
_NN>std::common_type_t<decltype(ts)...> result;
_NN>bool found = ((pred(ts) ? (result = ts, true) : false) || ...);
_NN>// expands to: (pred(ts[0]) ? (result = ts[0], true) : false)
_NN>//          || (pred(ts[1]) ? (result = ts[1], true) : false)
_NN>//          || ...
_NN>


Интересно, такая размотка цикла происходит для наборов вот прямо любой длины? Или опять же, это на откуп компилятору? Тогда чего удивляться.
Re[2]: Трюки с fold expression
От: _NN_ www.nemerleweb.com
Дата: 08.06.20 12:44
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

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


_NN>>
_NN>>std::common_type_t<decltype(ts)...> result;
_NN>>bool found = ((pred(ts) ? (result = ts, true) : false) || ...);
_NN>>// expands to: (pred(ts[0]) ? (result = ts[0], true) : false)
_NN>>//          || (pred(ts[1]) ? (result = ts[1], true) : false)
_NN>>//          || ...
_NN>>


MD>Интересно, такая размотка цикла происходит для наборов вот прямо любой длины? Или опять же, это на откуп компилятору? Тогда чего удивляться.


Не ясен вопрос.
Спрашиваете сколько можно передать параметров в функцию с переменным набором параметров ?

Компилятор должен поддерживать до 256-ти:

— Parameters in one function definition [256].
— Arguments in one function call [256].


https://stackoverflow.com/questions/4582012/maximum-number-of-parameters-in-function-declaration
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Трюки с fold expression
От: kov_serg Россия  
Дата: 08.06.20 13:55
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Полезный набор

_NN>https://foonathan.net/2020/05/fold-tricks/

Как получить медиану из списка с помощью таких "трюков" ?
Re[2]: Трюки с fold expression
От: watchmaker  
Дата: 08.06.20 14:04
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Как получить медиану из списка с помощью таких "трюков" ?

1) зачем?
2) как минимум можно скомбинировать: берёшь рецепт взятия n-го элемента и подставляешь в него n = sizeof...(ts) / 2;
Re[3]: Трюки с fold expression
От: kov_serg Россия  
Дата: 08.06.20 14:24
Оценка: :)
Здравствуйте, watchmaker, Вы писали:

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


_>>Как получить медиану из списка с помощью таких "трюков" ?

W>1) зачем?
Вот именно. Нафига все эти трюки если всю подготовитеьлную работу можно выполнить до компиляции. Без "трюков", используя вменяемые языки программирования.
W>2) как минимум можно скомбинировать: берёшь рецепт взятия n-го элемента и подставляешь в него n = sizeof...(ts) / 2;
И где?
Re[3]: Трюки с fold expression
От: σ  
Дата: 09.06.20 05:35
Оценка: +1
_NN>Спрашиваете сколько можно передать параметров в функцию с переменным набором параметров ?

_NN>Компилятор должен поддерживать до 256-ти


Не должен, это рекомендации.

Annex B (informative) Implementation quantities
Re: Трюки с fold expression
От: rg45 СССР  
Дата: 09.06.20 13:02
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Полезный набор

_NN>https://foonathan.net/2020/05/fold-tricks/

_NN>Например

_NN>
_NN>for (auto elem : ts)
_NN>{
_NN>    if (pred(elem))
_NN>        return elem;
_NN>}
_NN>


_NN>==>


_NN>
_NN>std::common_type_t<decltype(ts)...> result;
_NN>bool found = ((pred(ts) ? (result = ts, true) : false) || ...);
_NN>// expands to: (pred(ts[0]) ? (result = ts[0], true) : false)
_NN>//          || (pred(ts[1]) ? (result = ts[1], true) : false)
_NN>//          || ...
_NN>


Пардон, но это же жульничество. Если ts — это variadic pack, то не скомпилируется первый вариант, а если нет, то второй. Эти варианты НЕ взаимозаменяемы. Ну либо я недопонял глубины иносказательности.

P.S. А все остальное, что есть по ссылке — какая-то банальщина.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 09.06.2020 13:09 rg45 . Предыдущая версия . Еще …
Отредактировано 09.06.2020 13:05 rg45 . Предыдущая версия .
Отредактировано 09.06.2020 13:03 rg45 . Предыдущая версия .
Re[2]: Трюки с fold expression
От: _NN_ www.nemerleweb.com
Дата: 09.06.20 13:10
Оценка:
Здравствуйте, rg45, Вы писали:

Почему не будет работать?


https://gcc.godbolt.org/z/GBW3Pk

#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
using namespace std;

template <typename Pred, typename F, typename... Ts>
void call_if_not_predicate(Pred pred, F f, Ts... ts)
{
    static_cast<void>(
         ((pred(ts) ? false : (f(ts), true)) && ...)
    );
}


int main()
{
   call_if_not_predicate(
       [](auto v){return v> 0;},
       [](auto v){cout << v << "\n";},
       -2, -1, 0, 1, 2);
}


-2
-1
0


R>P.S. А все остальное, что есть по ссылке — какая-то банальщина.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Трюки с fold expression
От: rg45 СССР  
Дата: 09.06.20 13:16
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Почему не будет работать?


_NN>https://gcc.godbolt.org/z/GBW3Pk


  Скрытый текст
_NN>
_NN>#include <memory>
_NN>#include <vector>
_NN>#include <iostream>
_NN>#include <algorithm>
_NN>#include <iterator>
_NN>#include <string>
_NN>using namespace std;

_NN>template <typename Pred, typename F, typename... Ts>
_NN>void call_if_not_predicate(Pred pred, F f, Ts... ts)
_NN>{
_NN>    static_cast<void>(
_NN>         ((pred(ts) ? false : (f(ts), true)) && ...)
_NN>    );
_NN>}


_NN>int main()
_NN>{
_NN>   call_if_not_predicate(
_NN>       [](auto v){return v> 0;},
_NN>       [](auto v){cout << v << "\n";},
_NN>       -2, -1, 0, 1, 2);
_NN>}
_NN>


_NN>

_NN>-2
_NN>-1
_NN>0



Так а где здесь "for (auto elem : ts)"? Где "было", а где "стало" — что с чем сравнивать?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Трюки с fold expression
От: _NN_ www.nemerleweb.com
Дата: 09.06.20 14:55
Оценка:
Здравствуйте, rg45, Вы писали:


R>Так а где здесь "for (auto elem : ts)"? Где "было", а где "стало" — что с чем сравнивать?


https://gcc.godbolt.org/z/nb5MoF

  "Как-то так"
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
using namespace std;

template <typename Pred, typename F, typename... Ts>
void call_if_not_predicate(Pred pred, F f, Ts... ts)
{
    // Suppress unused value warning
    static_cast<void>(
         ((pred(ts) ? false : (f(ts), true)) && ...)
    );
}


template <typename Pred, typename F, typename... Ts>
void call_if_not_predicate_v(Pred pred, F f, Ts... ts)
{
    for (auto v : {ts...})
    {
        if (pred(v))
            break;
        
        f(v);
    }
}

template <typename Pred, typename F, typename Container>
void call_if_not_predicate_c(Pred pred, F f, Container&& c)
{
   for (auto v : c)
   {
       if (pred(v))
          break;

       f(v);
   }
}
int main()
{
  auto pred = [](auto v){return v> 0;};
  auto f = [](auto v){cout << v << "\n";};

  cout << "fold\n";
   call_if_not_predicate(
       pred,
       f,
       -2, -1, 0, 1, 2);

    cout << "variadic with loop\n";
    call_if_not_predicate_v(
        pred,
        f,
        -2, -1, 0, 1, 2
    );


     cout << "container\n";
    int values[] = {-2, -1, 0, 1, 2};
    call_if_not_predicate_c(
        pred,
        f,
        values
    );
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Трюки с fold expression
От: rg45 СССР  
Дата: 11.06.20 05:25
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>
_NN>template <typename Pred, typename F, typename... Ts>
_NN>void call_if_not_predicate_v(Pred pred, F f, Ts... ts)
_NN>{
_NN>    for (auto v : {ts...})
_NN>    {
_NN>        if (pred(v))
_NN>            break;
        
_NN>        f(v);
_NN>    }
_NN>}
_NN>


Ну вот лично мне такая функция кажется притянутой за уши. Почему бы сразу не принять параметры в виде initializer_list? Вариадик паки же, до появления фолд экспрешенов, естественнее было бы обработать рекурсией. Циклы востребованы при работе с последовательностями элементов одного типа, чей размер не известен во время компиляции. В то время как фолд экспрешены наоборот — для последовательностей элементов разных типов и с размером, известным во время компиляции. Вот и выходит, что циклы и фолд экспрешены не конкуренты — в виду их разных областей применимости.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Трюки с fold expression
От: _NN_ www.nemerleweb.com
Дата: 11.06.20 05:29
Оценка:
Здравствуйте, rg45, Вы писали:

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


_NN>>
_NN>>template <typename Pred, typename F, typename... Ts>
_NN>>void call_if_not_predicate_v(Pred pred, F f, Ts... ts)
_NN>>{
_NN>>    for (auto v : {ts...})
_NN>>    {
_NN>>        if (pred(v))
_NN>>            break;
        
_NN>>        f(v);
_NN>>    }
_NN>>}
_NN>>


R>Ну вот лично мне такая функция кажется притянутой за уши. Почему бы сразу не принять параметры в виде initializer_list? Вариадик паки же, до появления фолд экспрешенов, естественнее было бы обработать рекурсией. Циклы востребованы при работе с последовательностями элементов одного типа, чей размер не известен во время компиляции. В то время как фолд экспрешены наоборот — для последовательностей элементов разных типов и с размером, известным во время компиляции. Вот и выходит, что циклы и фолд экспрешены не конкуренты — в виду их разных областей применимости.


Проверенно на практике, компилятор гораздо охотнее оптимизирует линейный код из fold expression чем рекурсию.
К тому же есть возможность передать разные типы, а не только один как в случае с initializer_list.
Мы заменили рекурсивный код времён C++14 на fold expression и получили более быстрый код, а так же немаловажно, более быструю компиляцию.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Трюки с fold expression
От: rg45 СССР  
Дата: 11.06.20 05:38
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>>>
_NN>>>template <typename Pred, typename F, typename... Ts>
_NN>>>void call_if_not_predicate_v(Pred pred, F f, Ts... ts)
_NN>>>{
_NN>>>    for (auto v : {ts...})
_NN>>>    {
_NN>>>        if (pred(v))
_NN>>>            break;
        
_NN>>>        f(v);
_NN>>>    }
_NN>>>}
_NN>>>



_NN>Проверенно на практике, компилятор гораздо охотнее оптимизирует линейный код из fold expression чем рекурсию.


Да кто же с этим спорит. Вопрос же в том, как выглядел код ДО этого. И вот оказывается, что тот код, который мы как бы улучшаем, полностью надуман.

_NN>К тому же есть возможность передать разные типы, а не только один как в случае с initializer_list.


Да как же ты передашь разные типы, если внутри функции все эти объекты все равно складываются в один initializer_list? У тебя это просто не скомпилируется.

_NN>Мы заменили рекурсивный код времён C++14 на fold expression и получили более быстрый код, а так же немаловажно, более быструю компиляцию.


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

P.S. Я против fold expressions ничего не имею, если что
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 11.06.2020 5:48 rg45 . Предыдущая версия . Еще …
Отредактировано 11.06.2020 5:43 rg45 . Предыдущая версия .
Отредактировано 11.06.2020 5:41 rg45 . Предыдущая версия .
Re[7]: Трюки с fold expression
От: Vain Россия google.ru
Дата: 11.06.20 15:49
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Проверенно на практике, компилятор гораздо охотнее оптимизирует линейный код из fold expression чем рекурсию.

У меня компилятор gcc ругался на замыкающую рекурсию в constexpr функции. Пришлось отказаться, так что не всё так однозначно.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.