This appears similar to Deduce template parameter value from concept, but I can't seem to make a functioning solution from the answer there.
I've created a predicate to use with find_if
:
template <class Array>
class c_str_array_eq {
static_assert(std::predicate<c_str_array_eq, const Array &>);
const char *str;
public:
explicit constexpr c_str_array_eq(const char *str) : str{str} {}
bool operator()(const Array &array) const {
return std::strncmp(str, array.data(), array.size()) != 0;
}
};
The purpose of this predicate is to search a collection of std::array
s (or array-like objects) for a c-style string.
However when trying to use this predicate, I end up with something like this:
struct my_object {
std::array<char, 256> str;
}
std::ranges::find_if(a_collection, c_str_array_eq<std::array<char, 256>>("foo"), &my_object::str);
How can I get the compiler to deduce the template parameter to c_str_array_eq
in this situation?
Predicates usually aren't templated. Instead, their call operator is templated, because it's the call operator that will trigger argument deduction when called by the standard library algorithms.
#include <cstring>
#include <array>
#include <vector>
class c_str_array_eq {
const char *str;
public:
explicit constexpr c_str_array_eq(const char *str) : str{str} {}
template <class Array>
requires requires (const Array& array)
{
array.data();
array.size();
std::strncmp(str, array.data(), array.size());
}
bool operator()(const Array &array) const {
return std::strncmp(str, array.data(), array.size()) != 0;
}
};
struct my_object {
std::array<char, 256> str;
};
int main()
{
std::vector<my_object> a_collection;
std::ranges::find_if(a_collection, c_str_array_eq("foo"), &my_object::str);
}
This is done by almost all standard library predicates like std::less, where the default void
template will have a templated operator()
that does the actual deduction at the call site.