Pull to refresh

Comments 8

вот как всегда с макросами — с одной стороны достаточно удобно и практично. С другой — можно использовать лямбду, и будет хоть и маленько подлиннее, но явно и читаемо. Возможно, такая штука была бы удобна в Qt'овском QObject::connect, но там в основном надо разрешать перегрузки сигналов, а для них такой макрос не подойдет. Итого изобретательность поощряю, но использовать не буду
Дело не в лямбде и обычной функции. Дело в том, что в строке
for_each(begin(int_c), end(int_c), f);
у f отсутствуют параметры, по которым компилятор мог бы разрешить перегрузку. Он не может выбрать между
void f(int i){} и
void f(string s){}, поскольку не видит в этой строке типа параметра (как и их кол-ва).
Напротив, для
[](int a) { return f(a); }
или полиморфной лямбды
[](auto a) { return f(a); }
(в качестве оболочки над f(a))
виден тип параметра а, что
позволяет компилятору разрешить перегрузку и подставить подходящую функцию.
(не вписался в 2 слова)
Не могли бы объяснить в двух словах, почему для обычных функций компилятор не может вывести типы, а для generic лямбды может?

Из-за того, что эта лямбда по сути template, включается какая-то SFINAE-магия?
Дело не в лямбде и обычной функции. Дело в том, что в строке
for_each(begin(int_c), end(int_c), f);
у f отсутствуют параметры, по которым компилятор мог бы разрешить перегрузку. Он не может выбрать между
void f(int i){} и
void f(string s){}, поскольку не видит в этой строке типа параметра (как и их кол-ва).
Напротив, для
[](int a) { return f(a); }
или полиморфной лямбды
[](auto a) { return f(a); }
(в качестве оболочки над f(a))
виден тип параметра а, что
позволяет компилятору разрешить перегрузку и подставить подходящую функцию.
(не вписался в 2 слова)

Когда лямбда мономорфная — тут вопросов нет.


Я имею ввиду, что


auto l = [](auto a) { return f(a); }

это по сути (gcc 7.3 это успешно компилирует)


auto l = []<typename T>(T a) { return f(a); };

Т.е. компилятору нужно выводить тип аргумента a, чтобы определить, нужно этот темплейт инстанциировать для int или для string.

Да, конечно. Тут уже речь идет не о перегрузке функций, а о сначала о выводе типа шаблона.
В строке вида
for_each(begin(int_c), end(int_c), [](auto a) { return f(a); });
Для for_each имеем
template <class _InIt, class _Fn>
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) {…

вывод типа _Fn, следовательно вывод типа а, следовательно разрешение перегрузки
f(a). Согласны?

Согласен. Но ведь и при передаче f, нужно так же выводить тип _Fn.


С точки зрения человека, имеющего только самые общие представления о внутреннем устройстве компилятора (т.е. меня), при передаче f вывести тип должно быть даже проще, т.к. у нас сразу же есть всего 2 кандидата:


  • _Fn == void (*)(int)
  • _Fn == void (*)(string)

А при передаче полиморфной лямбды компилятору, получается, нужно рассматривать "двойной" темплейт, т.к. условно говоря, тип нашей лямбды:


_Fn == decltype(l) == template<class TRet, class TArg> TRet (*)(TArg)
Sign up to leave a comment.

Articles