автоматическое затухание указателя лямбда - функции при переходе к шаблонной функции


Есть ли способ сделать лямбда-распад указателем, не приводя явно к правой сигнатуре? Это приведет к некоторому коду:

template<typename T> T call(T(*func)()){ return func(); }
int ptr(){ return 0; }
int main(){
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; }));
    auto ret3 = call([]{ return 0; });  //won't compile
}
Очевидно, что вызов call работает только в том случае, если лямбда распадается на указатель, но я предполагаю, что это может произойти только после выбора правильной перегрузки функции/шаблона. К сожалению, я могу думать только о решениях, которые включают шаблоны для создания лямбды с любой сигнатурой распада, поэтому я возвращаюсь к квадратному.
2 6

2 ответа:

Вы можете изменить свою лямбду, чтобы использовать унарный оператор +: +[]{ return 0; }

Это работает, потому что унарный плюс может быть применен к указателям и вызовет неявное преобразование в указатель функции.

Почему бы вам излишне ограничивать себя указателями функций без дефолтных аргументов и лямбдами без захватов, полностью исключив огромное семейство функторов (например, std::function, любые результаты std::bind и все остальное, что имеет подходящий operator())?

Лучше просто расширить сигнатуру функции:

template <typename F> 
auto call(F func) -> decltype(func()) { 
  return func(); 
}

int ptr() { return 0; }

int g(int i = 0) {return i;}

int main() {
    auto ret1 = call(ptr);
    auto ret2 = call((int(*)())([]{ return 0; })); //tedious, but works
    auto ret3 = call([]{ return 0; });  //ok now.

    auto ret4 = call(g); //ok now!
    int i = 42;
    auto ret5 = call([=]{return i;}); //works, too!
    auto ret6 = call(std::bind(g, i)); //and so on...
}