微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 std::span 的通用函数无法编译

如何解决使用 std::span 的通用函数无法编译

我想制作一个带有 isInstd::span 函数

这是我的尝试:

#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
}

如您所见,我可以通过执行此转换来绕过:

isIn(2,std::span<const int>(v));

但这很冗长,我想做这样的事情:

isIn(2,v);

有什么办法可以实现吗?

https://godbolt.org/z/czTs83

解决方法

这是您代码的 版本。

首先我们从两个概念开始; is_spanspannable

template<class T>
concept is_span = requires(T& a) {
    { std::span(a) } -> std::same_as<T>;
};
template<class T>
concept spannable = requires(T& a) {
    { std::span(a) };
} && !is_span<T>;

某物 spannable 可以推导出为 span 而不是一个。

然后我们写了两个重载:

constexpr bool isIn(const auto& x,is_span auto const& v)
{
    for (const auto& e : v)
        if (e == x)
            return true;
    return false;
}

constexpr bool isIn(const auto& x,spannable auto const& v)
{
    return isIn(x,std::span(v));
}

使用新语法。

然后我们再添加一个重载:

template<std::size_t N>
constexpr bool isIn(const auto& x,auto const(& v)[N])
{
    return isIn(x,std::span(v));
}

允许这种美味的语法:

static_assert( isIn( 7,{1,2,3,4,5,6,7} ));

Live example

现在您要做的就是将其固定。

“悲伤”的意思

static_assert( isIn('\0',"hello") );

为真,因为 "hello" 是一个以 '\0' 结尾的数组。

template<class T>
constexpr bool isIn(const auto& x,std::initializer_list<T> il)
{
    return isIn(x,std::span(il));
}
template<std::size_t N>
constexpr bool isIn(char x,char const(& v)[N])
{
    return isIn(x,std::span(v,v+N-1));
}

Live example

,

没有必要在像这样的泛型函数中使用 std::span

template <typename T1,typename T2>
bool isIn(T1&& x,T2 &&v) // always use universal references
{ 
    for (auto&& e : v)
        if (e == x)
            return true;
    return false;
}

int main()
{
    const int v[] = {1,4};
    isIn(2,v); // T2 is const &int[4]
    isIn(2,std::span<const int>{v}); // T2 is span<const int>
    isIn(2,std::list<int>(std::begin(v),std::end(v)) ); // T2 is list<int>
       // but list cannot be a span!

    isIn('l',"blablalba"); //works too,T2 is const &char[9]

    std::string_view s = "blablalba";
    isIn('l',s); // T2 is std::string_view&

}

这种方式适用于任何定义了 std::begin 和 std::end 的类型。

,

模板扣除没有转换/推广,

所以 const int (&)[4] 不能推导出为 std::span<const int /*,4*/>

您可能仍然提供重载来自己进行转换(注意避免无限递归调用):

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.
}

但是这里不需要 std::span

template <typename T,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;
}
,

此实现涵盖了我的所有用例。我认为它可能对其他人有用:

#include <stdio.h>
#include <initializer_list>
#include <string_view>

template <typename T1,typename T2>
bool isIn(const T1& x,const T2 &v)
{ 
    printf("generic\n");
    for (auto& e : v)
        if (e == x)
            return true;
    return false;
}

bool isIn(char x,const char* v)
{
    // NOTE: we have this specialization because we don't want to consider the null terminator
    printf("str\n");
    return isIn(x,std::string_view(v));
}

template <typename T1,std::initializer_list<T2> v)
{ 
    printf("initializer_list\n");
    for (auto& e : v)
        if (e == x)
            return true;
    return false;
}

int main()
{
    const int v[] = {1,v); // generic
    isIn(2,4}); // initializer_list
    isIn('l',"blabla"); // str
}

https://godbolt.org/z/d3nW73

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?