簡體   English   中英

使用std :: sort時禁止使用函子(繼承)?

[英]A functor(inherrited) is forbidden when using std::sort?

#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( 繼承FileSorter )的實例。

問題是std::sort函數無法用上面顯示以下錯誤消息的代碼進行編譯。

/usr/include/c++/4.8/bits/stl_algo.h:5483:5:錯誤:無法分配抽象類型為'FileSorter'的對象

我不了解這種行為。 據我所知,配備有operator () struct稱為functor ,它是將函數作為對象處理的好方法。

眾所周知, 子類的實例可以由父類的引用來引用。

但是上面的例子說的不一樣。

我應該進行哪些更改以使代碼正常工作?

如果我對c ++的概念有誤,請隨時責罵我。

完整的編譯錯誤消息在這里。

$ make
Scanning dependencies of target cpp_factory
[ 11%] Building CXX object CMakeFiles/cpp_factory.dir/libraries/src/FileLister.cpp.o
In file included from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:0:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h: In constructor ‘FilesList::FilesList(const string&, const string&, const FileSorter&)’:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: error: no matching function for call to ‘sort(std::vector<boost::filesystem::path>::iterator, std::vector<boost::filesystem::path>::iterator, const FileSorter&)’
         std::sort(this->begin(), this->end(), fileSorter);
                                                         ^
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: note: candidates are:
In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from /home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:11,
                 from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:
/usr/include/c++/4.8/bits/stl_algo.h:5447:5: note: template<class _RAIter> void std::sort(_RAIter, _RAIter)
     sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
     ^
/usr/include/c++/4.8/bits/stl_algo.h:5447:5: note:   template argument deduction/substitution failed:
In file included from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:0:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57: note:   candidate expects 2 arguments, 3 provided
         std::sort(this->begin(), this->end(), fileSorter);
                                                         ^
In file included from /usr/include/c++/4.8/algorithm:62:0,
                 from /home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:11,
                 from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: note: template<class _RAIter, class _Compare> void std::sort(_RAIter, _RAIter, _Compare)
     sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
     ^
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: note:   template argument deduction/substitution failed:
/usr/include/c++/4.8/bits/stl_algo.h: In substitution of ‘template<class _RAIter, class _Compare> void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<boost::filesystem::path*, std::vector<boost::filesystem::path> >; _Compare = FileSorter]’:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:109:57:   required from here
/usr/include/c++/4.8/bits/stl_algo.h:5483:5: error: cannot allocate an object of abstract type ‘FileSorter’
In file included from /home/ub1404/Application/cpp_factory/libraries/src/FileLister.cpp:5:0:
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:49:8: note:   because the following virtual functions are pure within ‘FileSorter’:
 struct FileSorter{
        ^
/home/ub1404/Application/cpp_factory/libraries/include/cpp_factory/files/FileLister.h:51:18: note:  virtual bool FileSorter::operator()(const boost::filesystem::path&, const boost::filesystem::path&) const
     virtual bool operator()(const boost::filesystem::path& p1, const boost::filesystem::path& p2) const =0;
                  ^
make[2]: *** [CMakeFiles/cpp_factory.dir/libraries/src/FileLister.cpp.o] Error 1
make[1]: *** [CMakeFiles/cpp_factory.dir/all] Error 2
make: *** [all] Error 2

如果您查看簽名,則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
}

這樣,您可以直接轉發用戶通過的內容並避免虛擬調度。

您的FileSorter參數默認為SortByExtension對象,而不是SortByName對象。 由於您尚未包括SortByExtension的來源,因此我將首先檢查SortByExtension的函數調用運算符的函數簽名是否為

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

如果基類簽名與派生類函數簽名之間存在任何差異,派生類函數將不會覆蓋基類,並且派生類將被視為抽象類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM