[英]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.