如何检查传递给函数的容器是否已排序,如果没有,则对其进行排序

How to check if a container passed to a function is sorted and sort it if not

本文关键字:排序 是否 如果没有 检查 何检查 函数      更新时间:2023-10-16

我有我们前段时间写的这个函数:

template <class C, class T>
static inline bool findClosestObject( const C& container, const TimeUnit& now, T& object );
  • C是 T 元素的容器
  • TimeUnit是一个封装日期和时间的类
  • T是具有TimeUnit信息
  • 的对象

此函数在容器中执行二分搜索(使用std::lower_bound)以查找最接近now的对象。

当我们进行二叉搜索时,必须对容器进行排序。这个函数在许多地方与许多种类的容器(C可以std::vectorstd::setstd::map......)一起使用。有时我们使用排序std::vector而不是std::set因为它们的内存管理更快,并且还用于历史问题以及与使用向量的其他代码段的兼容性。

问题是我在代码中找到了一个地方,开发人员使用未排序的容器调用findClosestObject......好虫...而且我无法安全地确定所有可以做到这一点的地方。

所以我现在需要通过在这种特定情况下对容器进行排序来防止这种情况(会很慢,但至少可以工作,并且保证函数返回我们希望它返回的内容)

所以我尝试修改我的函数:

template <class C, class T>
static inline const C& fixOrder( const C& container, C& temp )
{
if ( std::is_sorted( container.begin(), container.end() )
{
return container;
}
else
{
assert( false ); // to alert developper
// in Release, fix the issue to have function work!
temp = container;
std::sort( temp.begin(), temp.end() );
return temp;
}
}
template <class C, class T>
static inline bool findClosestObject( const C& originalContainer, const TimeUnit& now, T& object )
{
C temp;
const C& container = fixOrder( originalContainer, temp );
...
// leave old code unchanged
}

但是当Cstd::setstd::map时,这无法编译。因为std::sort不允许使用这种容器...

是否可以以这样一种方式编写fixOrder,即它只会为std::vector而不是为其他容器做事?

您可以只为std::set<T>添加部分专用化,为模板函数添加std::map<T1,T2>

// This one is called for every C not having a better specialization
template <class C>
static inline const C& fixOrder( const C& container, C& temp )
{
if ( std::is_sorted( container.begin(), container.end() ))
{
return container;
}
else
{
assert( false ); // to alert developper
// in Release, fix the issue to have function work!
temp = container;
std::sort( temp.begin(), temp.end() );
return temp;
}
}
// This one is called for std::set<T>
template<class T>
static inline const set<T>& fixOrder( const set<T>& container, set<T>& temp )
{
return container;
}
// This one is called for std::map<T1, T2>
template<class T, class T2>
static inline const map<T, T2>& fixOrder( const map<T, T2>& container, map<T, T2>& temp )
{
return container;
}

此答案包含有关模板函数重载解析的详细信息。

alexeykuzmin的回答更简单,应该可以解决你的问题。我下面的答案稍微复杂一些,但出于教育目的,这可能是一个有趣的读物。


fixOrder是否可以以这样一种方式编写,即它只会为std::vector而不是为其他容器做事?

是的!您可以使用std::enable_if和帮助程序is_specialization_of特征:

template <typename, template <typename...> class>
struct is_specialization_of : std::false_type
{
};
template <template <typename...> class TTemplate, typename... Ts>
struct is_specialization_of<TTemplate<Ts...>, TTemplate> : std::true_type
{
};
template <class C>
static inline auto fixOrder(const C& x, C&)
-> typename std::enable_if<is_specialization_of<C, std::vector>{}, const C&>::type
{
std::cout << "C is a vectorn";
return x;
}
template <class C>
static inline auto fixOrder(const C& x, C&)
-> typename std::enable_if<!is_specialization_of<C, std::vector>{}, const C&>::type
{
std::cout << "C is not a vectorn";
return x;
}

使用上面的代码...

int main() 
{
std::vector<int> v;
std::set<int> s;
fixOrder(v, v);
fixOrder(s, s);
}

。将打印:

C 是向量

C 不是向量

魔杖盒示例