问题
I have a vector of vectors, and I want to check if all of them are empty. Using the standard library, I tried:
#include <algorithm>
#include <vector>
int main()
{
std::vector<std::vector<int>> vv;
std::all_of(std::begin(vv), std::end(vv), std::empty);
}
This result in the following error in clang 7.0:
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/stl_algo.h:508:5: note: candidate template ignored: couldn't infer template argument '_Predicate'
I guess it's a standard behavior, due to the rules of type deduction. But anyway, what i the easiest way to workaround this?
EDIT: I accepted rubenvb's answer, because he gave a simple and reasonable explanation, together with the natural workaround. all_of accepts a predicate, which is a function, a function object or a lambda expression. std::empty is neither of those, but a function template. When explicitly instantiating it, we get a plain function which should work. Surprisingly, it's still not compile on most compilers I tried.
Well, lets see:
on GCC 6.3, it compiles just fine - https://godbolt.org/g/Pxta7C
but on GCC from trunk, it causes an internal compiler error - https://godbolt.org/g/H6DHt5
Neither Clang from trunk or MSVC 2017 succeed to compile it:
https://godbolt.org/g/819pbQ (Clang)
https://godbolt.org/g/ua5E8e (MSVC)
EDIT2: Apparently, Robert Andrzejuk is right too: the reason that the compiler cannot handle it is an ambiguous overload resolution. std::empty has 3 different overloads. and two of them are equally well candidates: the general one and the std::initializer list one. I achieved similar results with the following minimal version:
#include <vector>
template<class T>
void foo(const T& t);
template<class T>
void foo(const std::initializer_list<T>& il);
template<class F>
void bar(F f);
int main()
{
bar(foo<std::vector<int>>);
}
There is one difference, though. This example simply not compile in GCC from trunk (instead of causing an ICE).
回答1:
Unfortunately there is a problem to distinguish overloaded template functions as std::all_of
is also a template function. Better explaination: std::function fails to distinguish overloaded functions
So to do this, a static_cast
to the correct function type: bool ( * )( const std::vector< int >& )
is required:
std::all_of( vv.begin(), vv.end(),
static_cast< bool ( * )( const std::vector< int >& ) >( std::empty ) );
Using knowledge about the required static_cast
we can make a helper template function to deduce the correct definition from the container type:
The helper function:
template< typename C >
inline auto overloaded_pred_for( const C&, bool ( *f )( const C& ) ) -> decltype( f )
{
return f;
}
Example of it's usage:
std::all_of( vv.begin(), vv.end(),
overloaded_pred_for( std::vector< int >(), std::empty ) );
回答2:
fast workaround
#include <algorithm>
#include <vector>
int main() {
std::vector<std::vector<int>> vv;
std::all_of(std::begin(vv), std::end(vv),
[](const auto &v) {return std::empty(v);});
}
回答3:
what i the easiest way to workaround this?
Maybe
std::all_of(std::begin(vv), std::end(vv),
[](auto const & v){ return v.empty(); });
?
回答4:
std::empty is a function template, and as such not a callable object in and of itself. By explicitly providing the template parameters, you turn the function template name into a concrete instantiation, which is callable:
#include <algorithm>
#include <iterator>
#include <vector>
int main()
{
std::vector<std::vector<int>> vv;
std::all_of(std::begin(vv), std::end(vv), std::empty<std::vector<int>>);
}
Live demo (which incidentally crashes the compiler). Also note this GCC version apparently needed an #include <iterator>
even though it is explicitly mentioned std::empty
should come in with e.g. #include <vector>
...
回答5:
The problem is that there is not such a thing as std::empty, it's a member function as far as I know. Try using [](const auto& i){ return i.empty(); }
instead.
EDIT: well, I haven't seen std::empty before but as the commenter below pointed out it exists, but still you can use the lambda
来源:https://stackoverflow.com/questions/50566936/template-type-deduction-failing-stdempty-as-a-predicate