首先,我想特别强调 C++20 标签,因为我相信使用概念和
requires
语句更容易解决这个问题。
其次,当我在这里说数组时,我的意思是
int a[3]
,我已经有一个工作重载来处理“正常”std容器,包括array<int, 3> b
(另一个用于map
类容器,另一个用于queue
) -类似容器)。
我有一个带有大量重载的大型函数,可以使用新概念和
requires
关键字来处理不同类型,以使每个重载处理尽可能多的类型。
我找不到正确区分数组和指针的方法。我想要一种永远不会将指针错误分类为数组的方法,但是如果某些数组被分类为指针,那并不是世界末日(值得注意的是,如果一个数组只有一个元素,那么它被分类为哪个元素根本不重要)如)。
这个答案很接近,但它不适用于我不知道数组是什么/指针是什么的一般情况。
现在我将其用于数组:
template<typename T> requires(requires(T& a){1[a];}
&& !requires(T& a){a.begin();}
&& !is_convertible_v<T, string>
)
string function(const T& v);
这是指针:
template<typename T> requires(is_pointer_v<T>
&& !requires(T& a){1[a];}
&& !is_convertible_v<T, string>
)
string function(T v);
这至少可以将指向字符串的类用作指针,但我尝试的其他所有内容都被归类为数组。
我认为
<type_traits>
的 is_array_v<T>
可以在这里工作;如果我将它添加到我对数组的要求中,并在我对指针的要求中将 !requires(T& a){1[a];}
替换为 !is_array_v<T>
,那么指针将按预期工作,但我会得到一个不明确的数组重载错误,因为它隐式地将其转换为指针。我的印象是隐式转换在模板实例化中不起作用。
您可以根据传递的函数参数进行函数模板重载,而不是使用
requires
使用约束。
由于在代码片段的数组版本中您是通过引用传递的,因此您只需将参数更改为
const T (&ref)[N]
即可,如下所示。同样,由于在指针版本中您是按值传递的,因此您只需将其参数更改为 T*
,如下所示:
//for arrays only
template<typename T, std::size_t N> void func(const T(&ref)[N])
{
}
//for pointers only
template<typename T> void func(T*)
{
}