C++ 使用std::span的通用函数不';不编译

C++ 使用std::span的通用函数不';不编译,c++,c++20,std-span,C++,C++20,Std Span,我想做一个isIn函数,它接受std::span 这是我的尝试: #包括 模板 布尔isIn(常数T1和x,标准::跨度v) { 用于(常数T2&e:v) 如果(e==x) 返回true; 返回false; } //这一个可以工作,但我希望我的函数是泛型的 /*布尔isIn(整数x,标准::跨度v) { for(int e:v) 如果(e==x) 返回true; 返回false; }*/ int main() { 常数int v[]={1,2,3,4}; isIn(2,v);//我想要这个,但不

我想做一个
isIn
函数,它接受
std::span

这是我的尝试:

#包括
模板
布尔isIn(常数T1和x,标准::跨度v)
{
用于(常数T2&e:v)
如果(e==x)
返回true;
返回false;
}
//这一个可以工作,但我希望我的函数是泛型的
/*布尔isIn(整数x,标准::跨度v)
{
for(int e:v)
如果(e==x)
返回true;
返回false;
}*/
int main()
{
常数int v[]={1,2,3,4};
isIn(2,v);//我想要这个,但不编译
//isIn(2,std::span(v));//这很好用
}
正如你所看到的,我可以通过做这个演员来四处走动:

isIn(2,std::span(v));
但这太冗长了,我想这样做:

isIn(2,v);
有什么办法可以实现吗


无需在以下通用函数中使用
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, 2, 3, 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&

}
模板
bool-isIn(T1&&x,T2&&v)//始终使用通用引用
{ 
用于(自动和e:v)
如果(e==x)
返回true;
返回false;
}
int main()
{
常数int v[]={1,2,3,4};
isIn(2,v);//T2是常数&int[4]
isIn(2,std::span{v});//T2是span
isIn(2,std::list(std::begin(v),std::end(v));//T2是list
//但列表不能是一个跨度!
isIn('l','blablalba');//也可以,T2是常量和字符[9]
std::string_view s=“blalba”;
isIn('l',s);//T2是std::string_视图&
}

这样,它将适用于定义了std::begin和std::end的任何类型。

模板推导没有转换/升级

因此,
const int(&)[4]
不能推断为
std::span

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


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

#包括
#包括
#包括
模板
布尔isIn(常数T1和x,常数T2和v)
{ 
printf(“通用\n”);
用于(自动和电气:v)
如果(e==x)
返回true;
返回false;
}
布尔isIn(字符x,常量字符*v)
{
/Note:我们有这个专门化,因为我们不想考虑空终止符。
printf(“str\n”);
返回isIn(x,std::string_视图(v));
}
模板
布尔isIn(常数T1和x,标准::初始值设定项\列表v)
{ 
printf(“初始值设定项列表”);
用于(自动和电气:v)
如果(e==x)
返回true;
返回false;
}
int main()
{
常数int v[]={1,2,3,4};
isIn(2,v);//泛型
isIn(2,{1,2,3,4});//初始值设定项\列表
isIn('l','blabla');//str
}
这是您的代码版本

首先,我们从两个概念开始<代码>是_span和
span可启用的

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>;
使用新语法

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

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

现在你要做的就是把它变成中缀

“悲哀”的意思是

是true,因为“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));
}
模板
constexpr bool isIn(const auto&x,std::initializer\u list il)
{
返回isIn(x,std::span(il));
}
模板
constexpr bool isIn(char x,char const&v)[N])
{
返回isIn(x,std::span(v,v+N-1));
}

.

is
isIn(2,v)工作?首先使用std::span有什么原因吗?没有它,代码就可以正常工作@阿德里安迈尔yes@Arpegius哇,我没想到Range for也能与C数组一起工作。谢谢@tuket您可以通过其他方式获取参数。也可能值得注意的是,您可以禁用演绎
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} ));
static_assert( isIn('\0', "hello") );
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));
}