cplus-plus.ru logo
Мы переехали на cplus-plus.ru
Главная страница В закладкиО сайтеКарта сайта
Хостинг от uCoz
Добавить в закладки

Меню сайта

Полезные ссылки

Наша рассылка
Подписаться на рассылку
"C++ : cplus-plus.ru :
Рассылка статей C++"


Друзья сайта
alsproject.ru Выбор выходного разделительного конденсатора

Приветствую Вас, Гость · rss 19-Апр-2024, 13:55
Главная » 2010 » Декабрь » 6 » C++0x: Конвертируем лямбда-выражение в указатель на функцию
15:02
C++0x: Конвертируем лямбда-выражение в указатель на функцию

C++0x: Конвертируем лямбда-выражение в указатель на функцию
По роду деятельности мне часто приходится иметь дело с вычислительными задачами. В них нередко нужно передавать указатель на функцию, чтобы, например, построить график этой функции, или решить уравнение. Кроме того, указатели на функцию обычно используются в различных GUI фреймворках, чтобы указать, какое действие будет совершено при нажатии на определённую кнопку.

В новом стандарте C++0x появились зымыкания. Не вдаваясь в подробности, замыкания — это такие объекты, которые позволяют создавать функции прямо в теле других функций. Если подробнее — замыкания позволяют создавать функциональные объекты — то есть объекты, для которых определён operator(). На хабре уже писали о них: например тут.

Мне очень понравилось нововведение и я начал им пользоваться. Но только вот незадача: по смыслу, замыкания и функции — почти одно и то же, а использовать замыкания там, где должны использоваться указатели на функции, сходу не получается. По стандарту, замыкания без списка захвата должны свободно конвертироваться в указатели на функции, но на практике такого не наблюдалось, видимо ещё не реализовано. И я задался вопросом, можно ли использовать замыкания там, где используются указатели на функции?

Рассмотрим пример. Пусть у нас уже есть функция printFunctionTable, которая позволяет распечатать таблицу значений функции, при этом аргумент пробегает значения от 1 до 10.

void printFunctionTable(int (*func)(int)){
for(int i=1;i<=10;i++) cout << func(i) << " ";
cout << endl;
}

Конечно мы могли бы переписать эту функцию сразу под замыкания, а не под указатели на функции, но такая функция может быть расположена в закрытой библиотеке (как чаще всего и бывает), поэтому будем искать способ конвертации одного в другое.

Так же определим функцию, значения которой нам нужно распечатать:

int square(int x){
return x*x;
}

Теперь напишем главную функцию, в которой выведем таблицу квадратов функций.

int main(void)
{
printFunctionTable(square);
return 0;
}

Компилируем и запускаем, получаем табличку:

1 4 9 16 25 36 49 64 81 100

Теперь попробуем провернуть то же самое с замыканием — кубом числа.

auto cube=[](int x){
return x*x*x;
}

printFunctionTable(cube);


Не выходит — при компиляции — ошибка! Конечно — типы то — разные!
Как же нам это обойти? На помощь нам придут шаблоны.


template <typename CL>
int closureToFunction(int x){
CL cl;
return cl(x);
}

Тут мы определили шаблон функции, параметризованный типом CL — то есть типом нашего замыкания. Всё что нам нужно от нашего замыкания — вызвать его и вернуть значение.

Теперь можно использовать замыкание в том месте, где мы раньше использовали указатель на функцию. Выглядеть это будет так:

printFunctionTable(closureToFunction<decltype(cube)>);

после компиляции и запуска, получаем табличку:

1 8 27 64 125 216 343 512 729 1000

Уррра!!! — работает! =)

Для справки: decltype — это новое ключевое слово в C++0x, позволяющее определить тип выражения, то есть, в данном случае — тип нашего замыкания cube.

Вот собственно и всё — задача решена, теперь мы можем в удобном виде определять функции для каких-то действий прямо по ходу текста программы, а не скакать туда-сюда по исходнику, чтобы оформлять эти действия в отдельные функции.

Дополнительно хочется отметить, что мы создали только шаблон для сигнатуры int(int). По мере надобности можно добавлять и другие сигнатуры — double(int,double) к примеру, итд. Также, для удобства можно сделать макрос

#define CLOSURE_TO_FUNCTION(cl) closureToFunction<decltype(cl)>

P.S. Тестировалось на компиляторе Intel C++ Compiler 11.1, по идее, должно работать в g++ 4.5 и в visual studio 2010, главное не забыть проставить при компиляции флаги, позволяющие использовать c++0x.

Полный код программы:

#include <iostream>

using namespace std;

void printFunctionTable(int (*func)(int)){
for(int i=1;i<=10;i++) cout << func(i) << " ";
cout << endl;
}

int square(int x){
return x*x;
}

template int closureToFunction(int x){
CL cl;
return cl(x);
}

#define CLOSURE_TO_FUNCTION(cl) closureToFunction <decltype(cl)>

int main(void)
{
printFunctionTable(square);

auto cube=[](int x){return x*x*x;};
auto quad=[](int x){return x*x*x*x;};

printFunctionTable(CLOSURE_TO_FUNCTION(cube));
printFunctionTable(CLOSURE_TO_FUNCTION(quad));

return 0;
}

Автор текста:ScratchBoom
Источник:http://habrahabr.ru
Источник: C++0x: Конвертируем лямбда-выражение в указатель на функцию
Категория: Новости | Просмотров: 503 | Добавил: FazaNaka | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]