对于代码,正如您编写的那样,C++ 的答案与 C 的答案基本相同:当且仅当所涉及的两个指针引用同一数组的一部分时,您才会得到定义的行为,或者一个结束(正如@bathsheba 已经指出的那样,非数组对象被视为与一个项目的数组相同)。
然而,C++ 确实添加了一个可能有用的问题:即使在应用于这样做需要从<functional> 指向分离对象std::less<T> 和朋友的指针。所以,给定两个像这样的独立对象:
Object a;
Object b;
...将两个对象的地址与比较对象进行比较必须“产生一个严格的总顺序,该顺序在这些特化之间是一致的,并且也与内置运算符 、=。” (N4659,[比较]/2)。
因此,您可以像这样编写函数:
template <typename Ty>
bool in_range(const Ty *test, const Ty *begin, const Ty *end)
{
return std::less_equal<Ty *>()(begin, test) && std::less<Ty *>()(test, end);
}
如果你真的想保持原来的函数签名,你也可以这样做:
template <typename Ty>
bool in_range(const Ty *test, const Ty *r, size_t n)
{
auto end = r + n;
return std::less_equal<Ty *>()(r, test) && std::less<Ty *>()(test, end);
}
[请注意,我使用std::less_equal 编写第一个比较,使用std:less 编写第二个比较,以匹配通常预期的C++ 语义,其中范围定义为[begin, end)。 ]
这确实带有一个附带条件:您需要确保 r 指向至少包含 n 项1 的数组的开头,否则 auto end = r + n; 将产生未定义的行为。
至少对于我所期望的这种函数的典型用例,您可以稍微简化使用,但通过传递数组本身,而不是指针和显式长度:
template <class Ty, size_t N>
bool in_range(Ty (&array)[N], Ty *test) {
return std::less_equal<Ty *>()(&array[0], test) &&
std::less<Ty *>()(test, &array[0] + N);
}
在这种情况下,您只需传递数组的名称和要测试的指针:
int foo[10];
int *bar = &foo[4];
std::cout << std::boolalpha << in_range(foo, bar) << "\n"; // returns true
这个只有支持测试实际数组。如果您尝试将非数组项作为第一个参数传递,它将无法编译:
int foo[10];
int bar;
int *baz = &foo[0];
int *ptr = new int[20];
std::cout << std::boolalpha << in_range(bar, baz) << "\n"; // won't compile
std::cout << std::boolalpha << in_range(ptr, baz) << "\n"; // won't compile either
前者可能会防止一些事故。后者可能不太理想。如果我们想同时支持两者,我们可以通过重载来实现(对于所有三种情况,如果我们选择的话):
template <class Ty, size_t N>
bool in_range(Ty (&array)[N], Ty *test) {
return std::less_equal<Ty *>()(&array[0], test) &&
std::less<Ty *>()(test, &array[0]+ N);
}
template <class Ty>
bool in_range(Ty &a, Ty *b) { return &a == b; }
template <class Ty>
bool in_range(Ty a, Ty b, size_t N) {
return std::less_equal<Ty>()(a, b) &&
std::less<Ty>()(b, a + N);
}
void f() {
double foo[10];
double *x = &foo[0];
double bar;
double *baz = new double[20];
std::cout << std::boolalpha << in_range(foo, x) << "\n";
std::cout << std::boolalpha << in_range(bar, x) << "\n";
std::cout << std::boolalpha << in_range(baz, x, 20) << "\n";
}
1. 如果你想获得真正的技术,它不必指向数组的开头——它只需要指向数组中至少有n 项的数组的一部分。