lambda overload set
От: alexeiz  
Дата: 05.11.12 07:17
Оценка: 208 (15) -1
Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции. Что-то вроде перегрузки функций, только для лямбд.

    auto f = overload(
        [] { return 1; },                // 1
        [] (int x) { return x + 1; },    // 2
        [] (double x) { return 2 * x; }  // 3
        );

    using std::cout;
    using std::endl;
    cout << f() << endl         // call 1
         << f(1) << endl        // call 2
         << f(2.0) << endl;     // call 3


Как это реализовать, спросите? Через наследование от лямбда функций!

template <typename ...Funcs>
struct overload_set;

template <typename Head, typename ...Tail>
struct overload_set<Head, Tail...> : Head, overload_set<Tail...>
{
    overload_set(Head head, Tail... tail)
        : Head{head}
        , overload_set<Tail...>{tail...}
    {}

    using Head::operator();
    using overload_set<Tail...>::operator();
};

template <typename Func>
struct overload_set<Func> : Func
{
    overload_set(Func func)
        : Func{func}
    {}

    using Func::operator();
};

template <typename ...Funcs>
overload_set<Funcs...> overload(Funcs... funcs)
{
    return overload_set<Funcs...>{funcs...};
}
Re: lambda overload set
От: Evgeny.Panasyuk Россия  
Дата: 05.11.12 10:16
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции.


Может пригодится — Boost.Functional/OverloadedFunction
Re: О дивный новый мир
От: B0FEE664  
Дата: 05.11.12 10:20
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции. Что-то вроде перегрузки функций, только для лямбд.


Почему "налету"? Это же статическое "связывание". Разве нет?

Кстати, здесь overload:
A>    auto f = overload(
A>


А здесь overload_set:
A>template <typename ...Funcs>
A>struct overload_set;

Это ошибка?
И каждый день — без права на ошибку...
Re: lambda overload set
От: Шахтер Интернет  
Дата: 05.11.12 10:27
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции. Что-то вроде перегрузки функций, только для лямбд.


Мысль интересная, но у меня один вопрос -- зачем это нужно? Есть какой-то практический случай, когда этот приём может быть полезен?
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: lambda overload set
От: Alexander G Украина  
Дата: 05.11.12 10:41
Оценка: 8 (1)
Можно мешать лямбды с другими функциональными объектами:

double mul(double x, double y) { return x*y; }
 
int main()
{
    using namespace std::placeholders;
    
    auto f = overload(
        [] { return 1; },                // 1
        [] (int x) { return x + 1; },    // 2
        std::bind(mul, 2, _1)  // 3
        );
 
    using std::cout;
    using std::endl;
    cout << f() << endl         // call 1
         << f(1) << endl        // call 2
         << f(2.0) << endl;     // call 3
}


Думаю, можно сделать даже перегрузку bind'ов , убив лишние SFINAE через какой-нибудь std::bind<lazy_enable_if<...>>
Re[2]: О дивный новый мир
От: flаt  
Дата: 05.11.12 10:41
Оценка: 1 (1)
Здравствуйте, B0FEE664, Вы писали:

BFE>Кстати, здесь overload:

BFE>А здесь overload_set:
BFE>Это ошибка?

Там ниже функция создания:
overload(Funcs... funcs)
Re[2]: О дивный новый мир
От: jazzer Россия Skype: enerjazzer
Дата: 05.11.12 10:47
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


A>>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции. Что-то вроде перегрузки функций, только для лямбд.


BFE>Почему "налету"? Это же статическое "связывание". Разве нет?


Налету — в смысле, локально (можно прямо внутри выражения), не выписывая где-то далеко отдельный функтор.

BFE>Кстати, здесь overload:

BFE>А здесь overload_set:
BFE>Это ошибка?

overload — это функция, возвращающая overload_set. Типа make_pair и pair, чтоб не указывать шаблонные аргументы.
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]: lambda overload set
От: jazzer Россия Skype: enerjazzer
Дата: 05.11.12 10:50
Оценка: 4 (1)
Здравствуйте, Шахтер, Вы писали:

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


A>>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции. Что-то вроде перегрузки функций, только для лямбд.


Ш>Мысль интересная, но у меня один вопрос -- зачем это нужно? Есть какой-то практический случай, когда этот приём может быть полезен?


Например:
http://www.rsdn.ru/forum/cpp/2899831.1
Автор: jazzer
Дата: 02.04.08


Ну и вообще, когда у тебя несколько разных функций, а ты хочешь сделать из них одну, но перегруженную (например, собрать сишные log,logf,logl в одну log):
auto log = overload( [](double x)      { return log(x); }
                   , [](float x)       { return logf(x); }
                   , [](long double x) { return logl(x); } )


Или наоборот, когда у тебя перегруженная функция, но ты хочешь ограничить ее перегрузные возможности:
auto log2 = overload( [](double x) { return log(x); }
                    , [](float x)  { return log(x); } )
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: lambda overload set
От: rg45 СССР  
Дата: 05.11.12 11:25
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции. Что-то вроде перегрузки функций, только для лямбд.

A>[...]
A>Как это реализовать, спросите? Через наследование от лямбда функций!
A>
A>template <typename ...Funcs>
A>struct overload_set;

A>template <typename Head, typename ...Tail>
A>struct overload_set<Head, Tail...> : Head, overload_set<Tail...>
A>{
A>    overload_set(Head head, Tail... tail)
A>        : Head{head}
A>        , overload_set<Tail...>{tail...}
A>    {}

A>    using Head::operator();
A>    using overload_set<Tail...>::operator();
A>};

A>template <typename Func>
A>struct overload_set<Func> : Func
A>{
A>    overload_set(Func func)
A>        : Func{func}
A>    {}

A>    using Func::operator();
A>};
A>


Класс!

Наследование от лямбд можно было бы упростить:
template <typename ...Funcs>
struct overload_set : Funcs...
{
    overload_set(Funcs... funcs) : Funcs(funcs)... { }
};

но не ясно, можно ли в таком варианте устранить неоднозначность operator()-ов. Конструкция using Funcs::operator()... не прокатывает
Никогда не говори "никогда". Всегда говори "иногда".
--
Re: lambda overload set
От: Serg27  
Дата: 05.11.12 12:26
Оценка: 84 (2) +1 -1
Здравствуйте, alexeiz, Вы писали:

A>Недавно где-то увидел интересную идею, заключающуюся в том,

Мне одному что-ли резанула эта фраза без ссылки на авторов идеи?

Сделал поиск в google по фразе "struct overload_set;" первые же две ссылки относятся к делу. По первой ссылке — здесь идет такой текст:

I recently read about a neat trick regarding overloading of lambda expressions in C++ in a blog post by Dave Abrahams here. This technique was originally described by Mathias Gaunard.


Т.е. в отличие от топикстартера в этом посте честно приведены ссылки на авторов идеи.

Вот ведь какая память — название классов помним, а авторов не помним... [сарказм]
Нет слов больше...
Re[2]: lambda overload set
От: rg45 СССР  
Дата: 05.11.12 13:18
Оценка:
Здравствуйте, Serg27, Вы писали:

A>>Недавно где-то увидел интересную идею, заключающуюся в том,

S>Мне одному что-ли резанула эта фраза без ссылки на авторов идеи?

S>Сделал поиск в google по фразе "struct overload_set;" первые же две ссылки относятся к делу. По первой ссылке — здесь идет такой текст:


S>

S>I recently read about a neat trick regarding overloading of lambda expressions in C++ in a blog post by Dave Abrahams here. This technique was originally described by Mathias Gaunard.


S>Т.е. в отличие от топикстартера в этом посте честно приведены ссылки на авторов идеи.


S>Вот ведь какая память — название классов помним, а авторов не помним... [сарказм]

S>Нет слов больше...

Все мы с удовольствием пользуемся всеми доступными нам благами цивилизации и достижениями научно-технического прогресса, не особо вспоминая тех, кто вложил в это труд и талант. Так и в этом случае. По крайней мере, человек честно сказал, что не сам это придумал. Ну не помнит, ну что тут поделаешь, так уж устроена человеческая память.
Никогда не говори "никогда". Всегда говори "иногда".
--
Re[3]: lambda overload set
От: Serg27  
Дата: 05.11.12 14:00
Оценка: +1
Здравствуйте, rg45, Вы писали:

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


Топикстартер дословно повторил реализацию overload_set из первой ссылки, которую я дал. Единственное изменение — замена имен параметров шаблона (F1 -> Head, Fs ->Tail). Вот всю реализацию дословно помнит, а где взял нет? А Google на что? Посмотрите на эту первую ссылку — там человек тоже захотел рассказать о красивом приеме, но на авторов то сослался. И это совершенно нормально. А то что произошло у нас на RSDN — не нормально.

А насчет "честно сказал, что не сам это придумал" это конечно плюс, человек не совсем потерял совесть, но эпоха списанных курсовых, дипломов, диссертаций довольно сильно размывает мораль. (ИМХО)
Re[2]: lambda overload set
От: B0FEE664  
Дата: 05.11.12 14:21
Оценка:
Здравствуйте, Serg27, Вы писали:

A>>Недавно где-то увидел интересную идею, заключающуюся в том,

S>Мне одному что-ли резанула эта фраза без ссылки на авторов идеи?
Мне — не резанула.

S>Т.е. в отличие от топикстартера в этом посте честно приведены ссылки на авторов идеи.

Вот я сомневаюсь, что они первые авторы идеи.

S>Вот ведь какая память — название классов помним, а авторов не помним... [сарказм]

S>Нет слов больше...
А в чём собственно дело? К чему тут искать авторство?

Я вот, например, помню, что одна из первых реализаций технологии signal-slot на templates была сделана каким-то программистом работающим в английской (ЕМНИП) компании. И он сожалел, что в С++ нет Variadic templates (давно это было) и в коде приходится вручную вбивать наборы функций для разного числа параметров, просил посодействовать в добавление в стандарт этой особенности. Ничего не напоминает?

Да и потом, такие идеи можно генерировать тысячами. И что? Для каждого случая будем авторство блюсти? Зачем?
И каждый день — без права на ошибку...
Re[2]: lambda overload set
От: alexeiz  
Дата: 05.11.12 16:06
Оценка:
Здравствуйте, Serg27, Вы писали:

S>

S>I recently read about a neat trick regarding overloading of lambda expressions in C++ in a blog post by Dave Abrahams here. This technique was originally described by Mathias Gaunard.


Точно! А я думал сначала, что где-то на Usenet-е.
Re[2]: lambda overload set
От: alexeiz  
Дата: 05.11.12 17:06
Оценка: 4 (1)
Здравствуйте, Шахтер, Вы писали:

Ш>Мысль интересная, но у меня один вопрос -- зачем это нужно? Есть какой-то практический случай, когда этот приём может быть полезен?


Во первых, интересна сама идея того, что ты берешь отдельные куски кода, объединяешь их вместе и получается новый кусок кода — Лисп одним словом.

А во вторых, постепенно стирается грань между лямбдами и обычными функциями. Если посмотреть поближе, в чем разница между:
auto foo     (int arg) -> void { ... }
auto foo = [](int arg}         { ... };


А если лямбды можно еще и перегружать, то лямбды и обычные функции становятся еще ближе. В C++14 может появиться возможность автоматически определять возвращаемое значение функции (вроде того, как это сейчас делается для лямбд), а лямбды могут стать полиморфными.
Re[2]: lambda overload set
От: alexeiz  
Дата: 05.11.12 19:02
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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


A>>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции.


EP>Может пригодится — Boost.Functional/OverloadedFunction


Посмотрел на реализацию — стена кода из BOOST_PP макросов. Пора начинать создавать C++11-only Boost.
Re[3]: lambda overload set
От: Erop Россия  
Дата: 05.11.12 20:39
Оценка:
Здравствуйте, rg45, Вы писали:

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


Мало того, он мог читать там, где авторов "уже забыли"...

В целом, если так уж интересно узнать кто там чего придумал, то сейчас это гуглится на ура обычно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: lambda overload set
От: Evgeny.Panasyuk Россия  
Дата: 05.11.12 20:40
Оценка: +1
Здравствуйте, alexeiz, Вы писали:

A>>>Недавно где-то увидел интересную идею, заключающуюся в том, что мы можем налету создать объект, который будет иметь много перегруженных operator()-ов, определяемых через лямбда функции.

EP>>Может пригодится — Boost.Functional/OverloadedFunction
A>Посмотрел на реализацию — стена кода из BOOST_PP макросов. Пора начинать создавать C++11-only Boost.

В Boost много мест, где при наличии C++11 код выражается во что-то простое, а при его отсутствии используется куча макросов. При этом наружу предоставляется одинаковый интерфейс.
Ничего плохого в этом не вижу, наоборот — честь и хвала авторам за то, что по возможности поддерживают старые стандарты .

P.S. далеко не везде использование C++11-only кода является экономически целесообразно
Re[2]: lambda overload set
От: jazzer Россия Skype: enerjazzer
Дата: 06.11.12 01:12
Оценка: +1
Здравствуйте, Serg27, Вы писали:

S>Вот ведь какая память — название классов помним, а авторов не помним... [сарказм]


Вообще-то "название класса" — это термин из Стандарта

Да и самой идее перегруженного функтора сто лет в обед и она много где появлялась и куча народу (включая меня) до нее самостоятельно успела дойти еще в рамках С++98, просто с вариадиками и лямбдами это более-менее по-человечески начало выглядеть.
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[3]: lambda overload set
От: flаt  
Дата: 06.11.12 12:57
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>А в чём собственно дело? К чему тут искать авторство?

Копирасты негодуют
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.