使用std :: sort时禁止使用仿函数(inherrited)?

时间:2016-03-30 13:02:53

标签: c++ sorting stl functor

#include <string.h>
#include <vector>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>

struct FileSorter{

virtual ~FileSorter(){}
    virtual bool operator()(const boost::filesystem::path& p1, const boost::filesystem::path& p2) const =0;
};

struct SortByName : public FileSorter{
    SortByName(bool ascending=true):ascending_order(ascending)
    {
    }

    virtual bool operator()(const boost::filesystem::path& p1, const boost::filesystem::path& p2) const {
        if(ascending_order)
            return p1.stem().string() < p2.stem().string();
        else
            return p1.stem().string() > p2.stem().string();
    }

protected:
    bool ascending_order;
};

class FilesList : public std::vector<boost::filesystem::path> {
public:
    FilesList(const std::string& dir, const std::string& f_regex, const FileSorter& fileSorter=SortByName()) {
        boost::regex e(f_regex, boost::regex::perl);
        boost::filesystem::path path(dir);
        if(!boost::filesystem::is_directory(path)) {
            throw std::runtime_error(path.string()+std::string(" is not a directory\n"));
        }

        for(boost::filesystem::directory_iterator file(path), f_end; file!= f_end; ++file){
            if(boost::regex_match(file->path().filename().string(), e))
                this->push_back(file->path());
        }

        std::sort(this->begin(), this->end(), fileSorter);
    }
};

我定义了一个类FileList,它确实执行创建符合正则表达式(f_regex参数)的文件列表。

要对列表进行排序,可以传递SortBy*** struct(从<{1}}继承)的实例。

问题是FileSorter函数无法使用上面的代码编译,显示以下错误消息。

  

/ usr / include / c ++ / 4.8 / bits / stl_algo.h:5483:5:错误:无法分配抽象类型'FileSorter'的对象

我不明白这种行为。在我的狭隘知识中,配备std::sort的结构称为仿函数,这是将函数作为对象处理的好方法。

正如我们所知,子类的实例可以通过父类的引用来引用。

但上面的例子说的不同。

我应该更改什么才能使代码生效?

如果我对c ++有错误的概念,请不要犹豫骂我。

完整的编译错误消息在这里。

operator ()

2 个答案:

答案 0 :(得分:4)

如果您查看签名,std::sort会按值获取其比较对象

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

所以当你写:

std::sort(this->begin(), this->end(), fileSorter);

你的对象被切片,你最终试图实例化一个按值抽取一个抽象类的函数,因此你最终得到的所有错误。

您需要做的是确保即使sort按值进行比较,也可以通过引用传递给您。谢天谢地,有一个应用程序!只需使用std::ref

std::sort(this->begin(), this->end(), std::ref(fileSorter));

那就是说,真的需要一个多态比较器吗?如果您只是将不同的比较函数对象传递到FilesList构造函数中,您应该更喜欢将其作为函数模板:

template <class Sorter>
FilesList(const std::string& dir, const std::string& f_regex, Sorter fileSorter) {
    // ...
    std::sort(begin(), end(), fileSorter); // now copying is fine
}

这样,您可以直接转发用户传递的内容并避免虚拟调度。

答案 1 :(得分:0)

您的FileSorter参数默认为SortByExtension对象而不是SortByName对象。由于您还没有包含SortByExtension的来源,我首先要检查SortByExtension的函数调用操作符的函数签名是

bool SortByExtension::operator()(const path&, const path&) const

如果基类和派生类函数签名之间存在任何差异,派生类函数将不会覆盖基类1,派生类将被视为抽象类。