Reputation: 1952
I would like to loop on a vector and filter out all the non-null-pointer elements. I'm looking for either an std
function that checks for something being a nullptr or an std
function that actually returns whatever is passed to it (like std::forward
), since a null pointer would evaluate to false
.
std::copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
std::is_pointer<ObjectType*>); // This does not compile
std::copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
std::forward<ObjectType*>); // This does not compile either
std::copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
static_cast<bool>); // This won't help me :)
std::copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
[] (const auto a) { return a; } ); // This is awkward
Upvotes: 3
Views: 247
Reputation: 303186
There is nothing like this directly in the standard library. Conceptually, the thing you'd want is:
std::copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
bool);
assuming you could use type names as factory functions that construct instances of that type. But, that's not a thing you can do in C++. At least directly. We can write that:
template <class T>
struct factory {
template <class... Args>
T operator()(Args&&... args) const {
return T(std::forward<Args>(args)...);
}
};
std::copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
factory<bool>{});
If you don't like typing {}
s, you could shorten this by making a variable template.
That said, the problem with this:
[](const auto a) { return a; } ); // This is awkward
isn't so much that it's awkward as much as it's inefficient - that's two copies (one in, one out). You'd want:
[](const auto& a) { return static_cast<bool>(a); }
Or really just force the bool
conversion earlier:
[](bool b){ return b; }
Upvotes: 1
Reputation: 137345
Stuck with the stuff in std
, you can use std::remove_copy_if
with std::logical_not
.
std::remove_copy_if(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
std::logical_not<ObjectType*>()); // or std::logical_not<> in C++14
Or, you can use remove_copy
passing nullptr
:
std::remove_copy(dynamicObjects.begin(), dynamicObjects.end(),
std::back_inserter(existingObjects),
nullptr);
If you really like copy_if
, you can use not_fn
or not1
on the logical_not
instead.
Upvotes: 5
Reputation: 275585
Nope.
I do find having identity
lying around to be useful sometimes:
struct identity_t {
template<class T>
T operator()(T&& t)const{ return std::forward<T>(t); }
constexpr identity_t() {}
};
constexpr identity_t identity;
(it converts rvalues to copies, for reference lifetime extension)
Mainly I use it when writing functions with optional mappings, like a transform-filter function: identity
is the default for transform, and always_true
is the default for filter.
Upvotes: 2