Vroomfondel
Vroomfondel

Reputation: 2898

Is there a std:: function which is usable as a predicate (similar to std::is_null_ptr)?

I had hoped for a short, concise, elegant:

std::array<int*,10> ip_arr;
bool all_null = std::all_of(ip_arr.begin(),ip_arr.end(),std::is_null_ptr_as_fn);

instead of inventing a lambda for that purpose:

std::array<int*,10> ip_arr;
bool all_null = std::all_of(ip_arr.begin(),ip_arr.end(),[](int *ip){ return ip == nullptr;});

which may even be suspicious because I ignored std::is_null_ptr and instead it should read like:

std::array<int*,10> ip_arr;
bool all_null = std::all_of(ip_arr.begin(),ip_arr.end(),[](int *ip){ std::is_null_ptr r(ip); return r();});

Yuck.

Upvotes: 2

Views: 445

Answers (3)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123440

There is no std::is_null_ptr. In case you refer to std::is_null_pointer, its a type trait to check if some type is nullptr_t. You have an array of int* there is no nullptr_t anywhere, the trait is of no help here.

Your version with the lambda is ok. Thats what lambdas were invented for. Do not expect to find functions for everything in the standard library.

PS: Also your request for a std::function is a little misguided. std::function is what you need for type erased callables. For example you want to store pointer to free function, an instance of a lambda, or others in the same variable, then you use a std::function. If you do not need type erasure, then you do not need std::function. std::function is not the type to be used whenever you pass functions around. Admittedly its name can be a bit confusing.

Upvotes: 4

Petr
Petr

Reputation: 10007

You can use std::indentity from C++20. As pointers can be implicitly converted to bool,

std::all_of(ip_arr.begin(), ip_arr.end(), std::identity());

will test if all pointers are not nullptrs.

To test if all pointers are null (as you are asking), you can use any_of and negate the result:

not std::any_of(ip_arr.begin(), ip_arr.end(), std::identity());

of invert the std::indentity result:

std::all_of(ip_arr.begin(), ip_arr.end(), std::not_fn(std::identity()));

Although your code with lambda may be more readable and easier to understand.

Upvotes: 7

user1350534
user1350534

Reputation:

The standard library provides several function objects for arithmetic and logical operations: https://en.cppreference.com/w/cpp/utility/functional

You can use logical_not to detect pointer null-ness.

bool all_null = std::all_of(ip_arr.begin(), ip_arr.end(), std::logical_not{});

Note that we're passing an instance of the function object (using {} or () to instance it).


As indicated by other answers and comments however, the lambda in your second code snippet might be considered more readable, with clearer intent, without relying on implicit pointer-to-bool conversion.

If you're seeking conciseness for this, or any other lambda predicate, you could name it for re-use:

auto is_null = [](auto *t) { return t == nullptr; };
bool all_null = std::all_of(ip_arr.begin(), ip_arr.end(), is_null);

or composition with other function objects:

bool all_null = std::none_of(ip_arr.begin(), ip_arr.end(), std::not_fn(is_null));

Upvotes: 1

Related Questions