I wanted to make an isIn
function that takes an std::span
.
This is my attempt:
#include <span>
template <typename T1, typename T2>
bool isIn(const T1& x, std::span<const T2> v)
{
for (const T2& e : v)
if (e == x)
return true;
return false;
}
// this one would work, but I want my function to be generic
/*bool isIn(int x, std::span<const int> v)
{
for (int e : v)
if (e == x)
return true;
return false;
}*/
int main()
{
const int v[] = {1, 2, 3, 4};
isIn(2, v); // I want this, but doesn't compile
//isIn(2, std::span<const int>(v)); // this works fine
}
As you can see, I can get around by doing this casting:
isIn(2, std::span<const int>(v));
But that's quite verbose, and I would like to do something like this:
isIn(2, v);
Is there any way that can be achived?
There are no conversion/promotion for template deduction,
so const int (&)[4]
cannot be deduced as std::span<const int /*, 4*/>
.
You might still provide overload to do the conversion yourself (care to avoid infinite recursive call):
template <typename T1, typename T2, std::size_t N>
bool isIn(const T1& x, std::span<const T2, N> v)
{
// return std::find(std::begin(v), std::end(v), x) != std::end(v);
for (const T2& e : v) {
if (e == x) {
return true;
}
}
return false;
}
template <typename T, typename C>
bool isIn(const T& x, const C&c)
{
return isIn(x, std::span(c)); // Use CTAD for the conversion.
}
But std::span
is not needed here:
template <typename T, typename C>
bool isIn(const T& x, const C& c)
{
// return std::find(std::begin(c), std::end(c), x) != std::end(c);
for (const auto& e : c) {
if (e == x) {
return true;
}
}
return false;
}