The std::not_fn function in C++ is a feature of the header, which was added in C++17. It serves a particular and useful purpose in functional programming by creating function objects that reverse the results of other callable entities like functions, function pointers, lambdas, or functors.
We often deal with predicates in functional programming and algorithmic scenarios, which are functions reliant on a condition and producing a boolean outcome (either true or false). At times, there may be a need to invert (negate) the logic of a current function instead of crafting a new predicate to verify the contrary condition. This is where std::not_fn proves to be beneficial.
Why is std::not_fn used?
The main function of std::notfn is to transform a given callable (function, lambda, or functor) into a new callable that reverses the output of the original one. This feature proves valuable in scenarios where algorithms demand an inverse condition compared to an existing predicate, like those found in std::findif, std::removeif, or std::allof. With std::not_fn, you can effortlessly flip the logic of a predicate without the need to manually invert its result through extra coding efforts.
Syntax:
It has the following syntax:
template <class Fn>
unspecified not_fn(Fn&& f);
Parameters:
- Fn: This is a callable entity that will have its result reversed, typically a function, function pointer, lambda expression, or functor.
Return value:
A callable entity (function object) that, upon execution, yields the opposite value of the initial function's output.
Program:
Let's consider a scenario to demonstrate the std::not_fn function in C++.
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // for std::not_fn
// A simple function to check if a number is even
bool is_even(int n) {
return n % 2 == 0;
}
// A functor to check if a number is positive
struct IsPositive {
bool operator()(int n) const {
return n > 0;
}
};
int main() {
std::vector<int> numbers = {10, -1, 25, 7, -8, 0};
// 1. Using std::not_fn with a function (is_even)
std::cout << "Odd numbers (negation of is_even): ";
std::for_each(numbers.begin(), numbers.end(), [](int n) {
if (std::not_fn(is_even)(n)) {
std::cout << n << " ";
}
});
std::cout << "\n";
// 2. Using std::not_fn with a functor (IsPositive)
std::cout << "Non-positive numbers (negation of IsPositive functor): ";
std::for_each(numbers.begin(), numbers.end(), [](int n) {
if (std::not_fn(IsPositive())(n)) {
std::cout << n << " ";
}
});
std::cout << "\n";
// 3. Using std::not_fn with a lambda function
auto is_greater_than_five = [](int n) { return n > 5; };
std::cout << "Numbers <= 5 (negation of lambda is_greater_than_five): ";
std::for_each(numbers.begin(), numbers.end(), [&](int n) {
if (std::not_fn(is_greater_than_five)(n)) {
std::cout << n << " ";
}
});
std::cout << "\n";
// 4. Using std::any_of to find if there are any negative numbers
bool has_negative = std::any_of(numbers.begin(), numbers.end(), std::not_fn(IsPositive()));
std::cout << "Any negative numbers? " << (has_negative ? "Yes" : "No") << "\n";
return 0;
}
Output:
Odd numbers (negation of is_even): -1 25 7
Non-positive numbers (negation of IsPositive functor): -1 -8 0
Numbers <= 5 (negation of lambda is_greater_than_five): -1 -8 0
Any negative numbers? Yes
Explanation:
Using {std::notfn} with functions, functors, and lambdas is demonstrated in this code. Because it negates the outcome of a callable, 'std::notfn' function is helpful when we wish to reverse a condition without having to write new logic.
- Function: To determine if a number is even, use the 'iseven' function. To check for odd numbers , we flip this reasoning and use {std::notfn(iseven)}. The odd integers are printed by the {std::foreach} loop because iterates across the vector.
- Functor: To determine whether an integer is positive, use the {IsPositive} functor. We obtain a callable that recognizes non-positive values by applying {std::not_fn(IsPositive)}, and the results are reported.
- Lambda: A lambda determines if a given value is more than 5. With this lambda, we use {std::not_fn} to print values that are less than or equal to 5.
- Algorithm: Finally, by negating the IsPositive functor, the std::any_of determines whether the vector contains any negative values.
Complexity Analysis
Time Complexity:
Each cycle of the std::foreach loop processes each item within the vector. As function invocations and std::notfn transformations remain constant in time for every iteration, the time complexity for each loop is O(n), where n represents the total count of elements in the vector.
On the downside, std::any_of exhibits a worst-case time complexity of O(n), since it scans through the complete range (or vector) to validate each element based on the given predicate. In scenarios where no element meets the criteria, the algorithm needs to assess all elements, leading to a linear time complexity.
Space Complexity:
Apart from iterators and temporary variables, which maintain a constant memory footprint irrespective of input size, all other operations exhibit an O(1) space complexity. This stability arises from the vector's size remaining unchanged throughout the operations, ensuring a consistent memory allocation for the algorithm's processing.