Каков тип лямбда-функции?
В C++0x мне интересно, какой тип имеет лямбда-функция. В частности:
#include<iostream>
type1 foo(int x){
return [x](int y)->int{return x * y;};
}
int main(){
std::cout<<foo(3)(4);//would output 12
type2 bar = foo(5);
std::cout<<bar(6);//would output 30
return 0;
}
что мне нужно заменить type1 / type2, чтобы заставить выше работать? Надеюсь, вы видите, чего я пытаюсь достичь, поэтому, даже если это невозможно путем прямой замены type1 и type2, возможно, вы можете направить меня в правильном направлении.
другими словами:
- как я могу получить функцию для возврата анонимной функции?
- как могу ли я назначить анонимную функцию переменной?
спасибо!
Edit: я компилирую с visual studio 2010
2 ответов
вы никогда не сможете узнать тип лямбда-функции, потому что логически происходит то, что компилятор генерирует (локальный) класс с перегруженным оператором вызова функции, а лексическое закрытие представлено членами данных этого (локального) класса. Это то, что логически происходит для лямбда-функции, такой как:
auto foo = [](int x, int y) { return x + y; };
компилятор логически делает следующее:
struct CompilerGeneratedName { void operator()(int x, int y) const { return x + y; } };
CompilerGeneratedName foo;
поскольку компилятор генерирует (местный) класс, он генерирует имя и поэтому вы никогда не можете явно напишите тип, вы можете вывести тип только из любого типа вычетов аргументов функции шаблона или с помощью auto/decltype.
также C++0x замыкания статически выделены, поэтому вы не могли бы безопасно вернуть необработанное закрытие C++0x в любом случае.
все еще есть несколько способов достичь этого, первый более гибкий и поддерживает лямбда-функции, которые захватывают лексические области. Используйте std:: function, если у вас есть лямбда-функция, которая ничего не захватывает из внешняя область затем вы можете использовать указатели функций, но это преобразование больше для работы с устаревшим кодом, чем что-либо.
поэтому в основном то, что вы хотите это:
std::function< int (int) > foo(int x)
{
return [x](int y)->int{return x * y;};
}
причина, по которой я продолжал говорить логически, заключается в том, что это то, как boost::Lambda работает изначально (хотя C++03 не позволяет локальным классам использоваться в аргументах функции шаблона) и где идея добавления лямбда-функций происходит от, но так как это языковая функция сейчас поставщики компиляторов могут реализовать его различными и более эффективными способами, например, при захвате всей среды по ссылке компилятор может просто передать указатель на стек вызовов вместо логического способа, сохраняя при этом логическое представление.
С Википедия:
лямбда-функции являются объектами функций типа, зависящего от реализации; имя этого типа доступно только компилятору. Если пользователь хочет принять лямбда-функцию в качестве параметра, тип должен быть шаблонным типом или он должен создать
std::function
для захвата значения лямбда.
VC10 компилирует это
//Beware, brain-compiled code ahead!
#include<iostream>
#include<functional>
std::function<int(int)> foo(int x)
{
return [x](int y)->int{return x * y;};
}
int main(){
std::cout<<foo(3)(4) << '\n';
auto bar = foo(5);
std::cout<<bar(6) << '\n';
return 0;
}
и печать
12 30