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

时间:2016-12-16 15:39:47

标签: c++ sorting c++11 vector stl

我有一段时间以前写的这个功能:

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而不是其他容器的方式编写?

2 个答案:

答案 0 :(得分:6)

您可以为模板函数添加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;
}

This answer包含有关模板函数重载解析的详细信息。

答案 1 :(得分:5)

alexeykuzmin's answer更简单,可以解决您的问题。我在下面的回答稍微复杂一点,但它可能是一个有趣的阅读教育目的。

  

可以用这样的方式编写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 vector\n";
    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 vector\n";
    return x;
}

使用上面的代码......

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

    fixOrder(v, v);
    fixOrder(s, s);
}

...将打印:

  

C是向量

     

C不是矢量

wandbox example