I am filling a std::vector with some object.
this vector instance as defined in the following line:
std::vector< std::list< pcl::PointXYZRGB>> tab;
I now want to delete the empty cells. I tried like following:
tab.erase(remove_if(tab.begin(), tab.end(), std::is_empty), tab.end());
I am getting the following error:
error: missing template arguments before ‘)’ token
voxels.erase(remove_if(voxels.begin(), voxels.end(), is_empty**)**, voxels.end());
I am confused, can someone tell me how I can do that?
std::is_empty
is a traits template. std::is_empty<X>
tells you if the type X
is an empty type -- that is, it is a struct {}
or class {}
with nothing inside it.
This is not what you want. First, because it cannot be called the way you need it to be called -- it has no operator()
that is useful to you -- and second, it takes a type, not an instance of a type, and answers questions about the type, not the instances.
auto list_is_empty = [](std::list<pcl::PointXYZRGB> const& l) {
return l.empty();
};
tab.erase(std::remove_if(tab.begin(), tab.end(), list_is_empty), tab.end());
will solve your problem. A better way to solve it would be:
struct container_is_empty_t {
template<class C>
bool operator()(C const& c)const{
return c.empty();
}
// not really needed, arrays of size 0 are non-standard
template<class T, size_t N>
bool operator()(T(&)[N])const{
return N > 0;
}
};
static container_is_empty_t const container_is_empty;
in some header file with utility code, then:
tab.erase(std::remove_if(tab.begin(), tab.end(), container_is_empty), tab.end());
does the same thing, but without being hard-coded to only work on std::list< pcl::PointXYZRGB>
s.
Or in c++14:
tab.erase(std::remove_if(tab.begin(), tab.end(), [](auto&& c){ return c.empty(); }, tab.end());
When doing the erase-remove idiom, if you forget the tab.end()
part, you'll get code that compiles but does the completely wrong thing in a pathological way.
I find it best to have
// erases elements from sequential container C if f(element) is true:
template<class C, class F>
auto erase_if( C& c, F f ) {
using std::begin; using std::end;
auto it = std::remove_if( begin(c), end(c), std::move(f) );
auto sz = std::distance( it, end(c) );
c.erase( it, end(c) );
return sz;
}
helper function to avoid that danger.
Then you get:
erase_if( tab, [](auto&& c){ return c.empty(); } );
which is nice and short.
The c++20 standard adds std::erase_if
to the language.