Question

Il semble que je devais inline un peu de code ici. Je me demande si elle est une mauvaise pratique de la conception de laisser cette entièrement dans un fichier d'en-tête comme ceci:

#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(), &currentData);
        if (hFind == INVALID_HANDLE_VALUE)
            WindowsApiException::ThrowFromLastError();
        while (!wcscmp(currentData.cFileName, L".") || !wcscmp(currentData.cFileName, L"..")) {
            increment();
        }
    };
    void increment() {
        BOOL success =
            FindNextFile(hFind, &currentData);
        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)

}}
Était-ce utile?

La solution

J'ai le code beaucoup plus dans certains de mes, si c'est de toute consolation. et ainsi de faire toutes les implémentations bibliothèque standard C ++, Boost et Microsoft (par exemple, ATL).

Autres conseils

La seule partie qui me semble être ouvert à la question beaucoup serait mise en oeuvre des fonctions DirectoryIteratorImpl. Ce n'est pas un modèle donc il n'a pas vraiment d'être dans un en-tête, et il a quelques routines un peu plus longues (le constructeur « réel » et l'incrément).

Les autres sont des modèles ou encore des composés de ces fonctions triviales que vous voulez voulez en ligne dans tous les cas (par exemple, les membres de FileData). Ceux-ci se retrouvent dans un en-tête dans tous les cas.

En ce qui concerne la longueur de l'en-tête va, vous pouvez avoir le code autant que vous le souhaitez dans vos fichiers d'en-tête. Le compromis est la quantité de code qui doit être recompilé chaque fois que votre programme est construit; le code placé dans vos fichiers du RPC peut être compilé dans des fichiers objets et liés dans chaque construction ultérieure.

Je suggère que chacun devrait être déplacé les définitions de méthode pour DirectoryIteratorImpl à un fichier .cpp. Si vous n'êtes pas la définition d'une ligne de méthode dans une définition de classe, il n'y a aucune raison pour qu'il soit inclus dans le fichier d'en-tête.

Un sans lien de côté: faut éviter d'écrire inline DirectoryIteratorImpl(); - en fait écrire vos fonctions en ligne en ligne, ou ne les marque pas en ligne. De C ++ FAQ Lite :

  

Il est généralement impératif que la définition de la fonction (la partie entre le {...})   être placé dans un fichier d'en-tête. Si vous mettez la définition de la fonction en ligne dans un Cpp   fichier, et si elle est appelée à partir d'un autre fichier .cpp, vous obtiendrez un « externe non résolu »   erreur de l'éditeur de liens.

Si vos fonctions sont « trop gros » pour écrire dans le fichier d'en-tête, ils sont trop gros pour ligne et le compilateur ignorera probablement votre suggestion en ligne de toute façon.

Il semble que vous programmez pour Windows ici, allons nous supposons que vous utilisez Visual Studio?

Quoi qu'il en soit, je ne pense pas qu'il y ait quelque chose comme trop de code en-têtes.

Il est une question de compromis pour la plupart:

  • compilation plus lent (mais nous avons multicoeurs et les en-têtes précompilés)
  • recompilation plus fréquents (encore une fois, multipaires)
  • peut-être météorisation code ...

Le seul point qui est ennuyeux (à mon avis) est le dernier ... et je besoin d'aide ici: sommes-nous que les fonctions allons inline, est-il possible que le compilateur et éditeur de liens décident de ne pas les inline et les transformer en un appel régulier?

Franchement, je ne vous inquiétez pas trop à ce sujet. Un certain nombre de bibliothèques Boost sont en-tête seule, même pour leurs parties non-modèle simplement parce qu'il facilite l'intégration (pas de lien nécessaire).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top