Search code examples
c++c++20std-span

Generic function using std::span doesn't compile


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?

https://godbolt.org/z/czTs83


Solution

  • 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;
    }