Задать вопрос
slarkevich
@slarkevich

Можно ли передать в функцию-предикат значение как в лямбду?

Например, нужно найти количество элементов вектора v, которые больше N. В случае с лямбдами можно написать так:
int N = 5;
count_if(begin(v), end(v), [N](int x) { return x > N; });


Но если предположить, что функция достаточно большая и оформлять ее через лямбду неудобно?
Тогда хотелось бы написать что-то вроде этого:
bool GreatherThanN(int x) {
    if (x > N) {
        return true;
    }
    return false;
}

count_if(begin(v), end(v), GreatherThanN);

Как в этом случае заставить функцию GreatherThanN увидеть это самое N?
  • Вопрос задан
  • 407 просмотров
Подписаться 2 Простой Комментировать
Решение пользователя Евгений Шатунов К ответам на вопрос (4)
@MarkusD Куратор тега C++
все время мелю чепуху :)
Лямбда - это объект неименованного типа, не являющегося типом объединеня или агрегатным типом.
Одним из свойств лямбды является то, что для случая с пустым замыканием лямбда неявно приводится к указателю на глобальную функцию. В ином случае лямбда - это объект-функтор, у которого определен operator().

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

Контекст можно расположить, скажем, в глобальном пространстве имен в виде глобальных переменных.
int N = 0;
bool GreatherThanN(int x) {
    if (x > N) {
        return true;
    }
    return false;
}

Такой подход, мягко говоря, неидеален. Его просто стоит знать, как врага, в лицо. :)

Другим способом является определение контекста через параметры шаблона функции:
template< int N >
bool GreatherThanN(int x) {
    if (x > N) {
        return true;
    }
    return false;
}

Инстанцирование функции из такого шаблона пройдет через оптимизации и с высокой вероятностью выродится в константу в месте вызова. Но N в этом случае надо знать на этапе компиляции. Да и в целом, не всё можно определить через параметры шаблона. Параметром шаблона может быть или тип, или константа целочисленного типа или типа сводимого к целочисленному (enum, bool, const char*, известные на этапе компиляции указатели).

Третьим случаем определения контекста является использование т.н. функторов - функциональных объектов.
Контекст в этом случае укладывается в объекте, а сама функция заключается в operator().
struct Comparator final
{
	int N;
	
	inline const bool operator () ( int x ) const
	{
		return x > N;
	}
};

// ...

Comparator GreatherThanN{ 10 };

// ...

count_if(begin(v), end(v), GreatherThanN);

Но с появлением лямбд в C++11 такой подход резко убавил в популярности, т.к. его задачи теперь с большим успехом решают лямбды.
Ответ написан
Комментировать