C++ 对于仅标头的库来说,这是否太多代码?
似乎我必须在这里内联相当多的代码。我想知道,将其完全保留在这样的头文件中是否是一种糟糕的设计实践:C++ 对于仅标头的库来说,这是否太多代码?,c++,header-files,header-only,C++,Header Files,Header Only,似乎我必须在这里内联相当多的代码。我想知道,将其完全保留在这样的头文件中是否是一种糟糕的设计实践: #include <list> #include <string> #include <boost/noncopyable.hpp> #include <boost/make_shared.hpp> #include <boost/iterator/iterator_facade.hpp> #include <Windows.h&g
#include <list>
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <Windows.h>
#include "../Exception.hpp"
namespace WindowsAPI { namespace FileSystem {
class NonRecursiveEnumeration;
class RecursiveEnumeration;
struct AllResults;
struct FilesOnly;
template <typename Filter_T = AllResults, typename Recurse_T = NonRecursiveEnumeration>
class DirectoryIterator;
template <typename Recurse_T>
struct FileData;
class NonRecursiveEnumeration : public boost::noncopyable
{
WIN32_FIND_DATAW currentData;
HANDLE hFind;
std::wstring root;
public:
NonRecursiveEnumeration() : hFind(INVALID_HANDLE_VALUE) {
};
NonRecursiveEnumeration(const std::wstring& pathSpec) {
std::wstring::const_iterator lastSlash =
std::find(pathSpec.rbegin(), pathSpec.rend(), L'\\').base();
if (lastSlash != pathSpec.end())
root.assign(pathSpec.begin(), lastSlash);
hFind = FindFirstFileW(pathSpec.c_str(), ¤tData);
if (hFind == INVALID_HANDLE_VALUE)
WindowsApiException::ThrowFromLastError();
while (!wcscmp(currentData.cFileName, L".") || !wcscmp(currentData.cFileName, L"..")) {
increment();
}
};
void increment() {
BOOL success =
FindNextFile(hFind, ¤tData);
if (success)
return;
DWORD error = GetLastError();
if (error == ERROR_NO_MORE_FILES) {
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
} else {
WindowsApiException::Throw(error);
}
};
~NonRecursiveEnumeration() {
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
};
bool equal(const NonRecursiveEnumeration& other) const {
if (this == &other)
return true;
return hFind == other.hFind;
};
const std::wstring& GetPathRoot() const {
return root;
};
const WIN32_FIND_DATAW& GetCurrentFindData() const {
return currentData;
};
};
//Not implemented yet
class RecursiveEnumeration : public boost::noncopyable
{
};
template <typename Recurse_T>
struct FileData //Serves as a proxy to the WIN32_FIND_DATA struture inside the iterator.
{
const Recurse_T* impl;
template <typename Filter_T, typename Recurse_T>
FileData(const DirectoryIterator<Filter_T, Recurse_T>* parent) : impl(parent->impl.get()) {};
DWORD GetAttributes() const {
return impl->GetCurrentFindData().dwFileAttributes;
};
bool IsDirectory() const {
return (GetAttributes() & FILE_ATTRIBUTE_DIRECTORY) != 0;
};
bool IsFile() const {
return !IsDirectory();
};
bool IsArchive() const {
return (GetAttributes() & FILE_ATTRIBUTE_ARCHIVE) != 0;
};
bool IsReadOnly() const {
return (GetAttributes() & FILE_ATTRIBUTE_READONLY) != 0;
};
unsigned __int64 GetSize() const {
ULARGE_INTEGER intValue;
intValue.LowPart = impl.GetCurrentFindData().nFileSizeLow;
intValue.HighPart = impl.GetCurrentFindData().nFileSizeHigh;
return intValue.QuadPart;
};
std::wstring GetFolderPath() const {
return impl->GetPathRoot();
};
std::wstring GetFileName() const {
return impl->GetCurrentFindData().cFileName;
};
std::wstring GetFullFileName() const {
return GetFolderPath() + GetFileName();
};
std::wstring GetShortFileName() const {
return impl->GetCurrentFindData().cAlternateFileName;
};
FILETIME GetCreationTime() const {
return impl->GetCurrentFindData().ftCreationTime;
};
FILETIME GetLastAccessTime() const {
return impl->GetCurrentFindData().ftLastAccessTime;
};
FILETIME GetLastWriteTime() const {
return impl->GetCurrentFindData().ftLastWriteTime;
};
};
struct AllResults
{
template <typename Recurse_T>
bool operator()(const FileData<Recurse_T>&) {
return true;
};
};
struct FilesOnly
{
template <typename Recurse_T>
bool operator()(const FileData<Recurse_T>& arg) {
return arg.IsFile();
};
};
#pragma warning(push)
#pragma warning(disable: 4355)
template <typename Filter_T, typename Recurse_T>
class DirectoryIterator : public boost::iterator_facade<DirectoryIterator<Filter_T>, const FileData<Recurse_T>, std::input_iterator_tag>
{
friend class boost::iterator_core_access;
boost::shared_ptr<Recurse_T> impl;
FileData<Recurse_T> derefData;
Filter_T filter;
void increment() {
do {
impl->increment();
} while (! filter(derefData));
};
bool equal(const DirectoryIterator& other) const {
return impl->equal(*other.impl);
};
const FileData<Recurse_T>& dereference() const {
return derefData;
};
public:
typedef FileData<Recurse_T> DataType;
friend struct DataType;
DirectoryIterator(Filter_T functor = Filter_T()) :
impl(boost::make_shared<Recurse_T>()),
derefData(this),
filter(functor) {
};
explicit DirectoryIterator(const std::wstring& pathSpec, Filter_T functor = Filter_T()) :
impl(boost::make_shared<Recurse_T>(pathSpec)),
derefData(this),
filter(functor) {
};
};
#pragma warning(pop)
}}
#包括
#包括
#包括
#包括
#包括
#包括
#包括“./Exception.hpp”
命名空间WindowsAPI{命名空间文件系统{
类非递归枚举;
类递归枚举;
结构所有结果;
结构文件;
模板
类目录迭代器;
模板
结构文件数据;
类非递归枚举:public boost::noncopyable
{
WIN32_FIND_DATAW currentData;
处理高频风;
std::wstring根;
公众:
非递归枚举():hFind(无效的句柄值){
};
非递归枚举(常量std::wstring和pathSpec){
std::wstring::const_迭代器lastSlash=
std::find(pathSpec.rbegin(),pathSpec.rend(),L'\\').base();
if(lastSlash!=pathSpec.end())
分配(pathSpec.begin(),lastSlash);
hFind=FindFirstFileW(pathSpec.c_str(),¤tData);
if(hFind==无效的句柄值)
WindowsApiException::ThrowFromLastError();
而(!wcscmp(currentData.cFileName,L.“)| |!wcscmp(currentData.cFileName,L.“.”){
增量();
}
};
无效增量(){
布尔成功=
FindNextFile(hFind和currentData);
如果(成功)
返回;
DWORD error=GetLastError();
如果(错误==错误\u没有\u更多\u文件){
FindClose(hFind);
hFind=无效的句柄值;
}否则{
WindowsApiException::抛出(错误);
}
};
~nonrecreasiveenumeration(){
if(hFind!=无效的句柄值)
FindClose(hFind);
};
布尔相等(常数非递归枚举和其他)常数{
如果(此==&其他)
返回true;
返回hFind==other.hFind;
};
常量std::wstring&GetPathRoot()常量{
返回根;
};
常量WIN32\u FIND\u DATAW&GetCurrentFindData()常量{
返回当前数据;
};
};
//尚未实施
类递归枚举:public boost::noncopyable
{
};
模板
struct FileData//充当迭代器中WIN32_FIND_数据结构的代理。
{
const Recurse_T*impl;
模板
FileData(const DirectoryIterator*parent):impl(parent->impl.get()){};
DWORD GetAttributes()常量{
返回impl->GetCurrentFindData().dwFileAttributes;
};
bool IsDirectory()常量{
返回(GetAttributes()&文件属性目录)!=0;
};
bool IsFile()常量{
return!IsDirectory();
};
bool IsArchive()常量{
返回(GetAttributes()&文件属性存档)!=0;
};
bool IsReadOnly()常量{
返回(GetAttributes()&文件属性只读)!=0;
};
未签名的\uuu int64 GetSize()常量{
ULARGE_整数值;
intValue.LowPart=impl.GetCurrentFindData().nFileSizeLow;
intValue.HighPart=impl.GetCurrentFindData().nFileSizeHigh;
返回intValue.QuadPart;
};
std::wstring GetFolderPath()常量{
返回impl->GetPathRoot();
};
std::wstring GetFileName()常量{
返回impl->GetCurrentFindData().cFileName;
};
std::wstring GetFullFileName()常量{
返回GetFolderPath()+GetFileName();
};
std::wstring GetShortFileName()常量{
返回impl->GetCurrentFindData().cAlternateFileName;
};
FILETIME GetCreationTime()常量{
返回impl->GetCurrentFindData().ftCreationTime;
};
FILETIME GetLastAccessTime()常量{
返回impl->GetCurrentFindData().ftLastAccessTime;
};
FILETIME GetLastWriteTime()常量{
返回impl->GetCurrentFindData().ftLastWriteTime;
};
};
结构所有结果
{
模板
bool运算符()(const FileData&){
返回true;
};
};
仅结构文件
{
模板
布尔运算符()(常量文件数据和参数){
返回arg.IsFile();
};
};
#pragma警告(推送)
#杂注警告(禁用:4355)
模板
类DirectoryIterator:public boost::iterator\u facade
{
朋友类boost::迭代器\u核心\u访问;
boost::共享\u ptr impl;
文件数据删除数据;
过滤器(T过滤器),;
无效增量(){
做{
impl->increment();
}而(!filter(derefData));
};
布尔相等(常量目录迭代器和其他)常量{
返回impl->equal(*other.impl);
};
常量FileData&dereference()常量{
返回数据;
};
公众:
typedef FileData数据类型;
友元结构数据类型;
DirectoryIterator(Filter\u T functor=Filter\u T()):
impl(boost::make_shared()),
derefData(本文件),
过滤器(函子){
};
显式目录迭代器(const std::wstring&pathSpec,Filter\u T functor=Filter\u T()):
impl(boost::make_shared(pathSpec)),
derefData(本文件),
过滤器(函子){
};
};
#布拉格警告(pop)
}}
如果有什么安慰的话,我的一些作品中有更多的代码。而且所有C++标准库实现,Boost和微软(例如,ATL)。< P>只要页眉的长度在你的头文件中,你可以拥有你想要的代码。取舍是每次构建程序时必须重新编译的代码量;放置在CPP文件中的代码可以编译成对象文件,并在每个后续生成中链接
我建议将directoryinteratorimpl
的每个方法定义都移动到.cpp
文件中。如果您没有在类定义中定义内联方法,则没有理由将其包含在头文件中
一个不相关的旁白:避免编写inline directoryinteratorimpl()代码>-实际将内联函数内联编写,或者不将其标记为内联。从:
函数的