Comments 8
вот как всегда с макросами — с одной стороны достаточно удобно и практично. С другой — можно использовать лямбду, и будет хоть и маленько подлиннее, но явно и читаемо. Возможно, такая штука была бы удобна в Qt'овском QObject::connect, но там в основном надо разрешать перегрузки сигналов, а для них такой макрос не подойдет. Итого изобретательность поощряю, но использовать не буду
+1
В Qt есть qOverload
https://doc.qt.io/qt-5/qtglobal.html#qOverload
0
Дело не в лямбде и обычной функции. Дело в том, что в строке
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 слова)
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 слова)
0
Не могли бы объяснить в двух словах, почему для обычных функций компилятор не может вывести типы, а для generic лямбды может?
Из-за того, что эта лямбда по сути template, включается какая-то SFINAE-магия?
Из-за того, что эта лямбда по сути template, включается какая-то SFINAE-магия?
+1
Дело не в лямбде и обычной функции. Дело в том, что в строке
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 слова)
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 слова)
0
Когда лямбда мономорфная — тут вопросов нет.
Я имею ввиду, что
auto l = [](auto a) { return f(a); }
это по сути (gcc 7.3 это успешно компилирует)
auto l = []<typename T>(T a) { return f(a); };
Т.е. компилятору нужно выводить тип аргумента a
, чтобы определить, нужно этот темплейт инстанциировать для int
или для string
.
+1
Да, конечно. Тут уже речь идет не о перегрузке функций, а о сначала о выводе типа шаблона.
В строке вида
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). Согласны?
В строке вида
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). Согласны?
0
Согласен. Но ведь и при передаче f
, нужно так же выводить тип _Fn
.
С точки зрения человека, имеющего только самые общие представления о внутреннем устройстве компилятора (т.е. меня), при передаче f
вывести тип должно быть даже проще, т.к. у нас сразу же есть всего 2 кандидата:
_Fn == void (*)(int)
_Fn == void (*)(string)
А при передаче полиморфной лямбды компилятору, получается, нужно рассматривать "двойной" темплейт, т.к. условно говоря, тип нашей лямбды:
_Fn == decltype(l) == template<class TRet, class TArg> TRet (*)(TArg)
+1
Sign up to leave a comment.
Помощь компилятору С++ в разрешении перегрузки функций