K
Kyku
Hello all,
I'm in a process of writing a small Linux C++ program for discovering
repeaded files over a filesystem. One part of this task is traversing a
directory structure. This is done by the following recursive function.
Since I'd like it to be general enough to handle function pointers and
function objects I've made it a template.
template <typename CallBack>
void Traverse(const std::string& path, CallBack& callback) throw
(PosixError);
This brings an interesting problem: if I make second parameter is const
(and I'd like it to be that way) then:
1) G++ 3.3.6 refuses to compile the program
error: no matching function for call to `Traverse(char*&, void
(&)(const std::string&))'
2) G++ 4.1.1 compiles the program but the callback is never executed
(i.e. no output) if the callback is function. Works fine if given a
function objects.
Is it some kind of compliler issue or maybe a C++ mistake in my code?
TIA, Kyku
Here's the working part of the program:
#include <string>
#include <cstddef>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
class PosixError : public std::exception
{
public:
PosixError() : _M_code(errno), _M_rep(strerror(_M_code)) {}
PosixError(int code) : _M_code(code), _M_rep(strerror(_M_code)) {}
int Code() const { return _M_code; }
const char* what() const throw() { return _M_rep.c_str(); }
~PosixError() throw() {}
private:
int _M_code;
std::string _M_rep;
};
class DirEntry
{
public:
const std::string& Name() { return _M_name; }
operator bool () const { return !_M_name.empty(); }
private:
DirEntry(struct dirent* dent) : _M_name(dent ? dent->d_name : "") {}
std::string _M_name;
friend class DirWalker;
};
class DirWalker
{
public:
DirWalker(const std::string& dirname) throw (PosixError) {
_M_dir = 0;
Open(dirname);
}
~DirWalker() { if (_M_dir != 0) closedir(_M_dir); }
operator bool () const { return _M_dir != 0; }
void Open(const std::string& dirname) throw (PosixError) {
Close();
_M_dir = opendir(dirname.c_str());
if (_M_dir == 0) throw PosixError();
}
void Close() {
if (_M_dir != 0) {
closedir(_M_dir);
_M_dir = 0;
}
}
DirEntry Read() throw(PosixError) {
const char* name;
struct dirent* dent;
do {
errno = 0;
dent = readdir(_M_dir);
if (errno != 0) throw PosixError();
name = dent->d_name;
} while (dent != 0 && name[0] == '.' && (name[1] == '\0' || name[1]
== '.' && name[2] == '\0'));
return DirEntry(dent);
}
private:
DIR* _M_dir;
};
template <typename CallBack>
void Traverse(const std::string& path, CallBack& callback) throw
(PosixError) {
DirWalker dw(path);
while (DirEntry de = dw.Read()) {
try {
struct stat buf;
std::string fullpath = path + '/' + de.Name();
if (stat(fullpath.c_str(), &buf) < 0) throw PosixError();
callback(fullpath);
if (S_ISDIR(buf.st_mode)) Traverse(fullpath, callback);
} catch (PosixError& pe) {
if (pe.Code() == EACCES) continue;
throw;
}
}
}
#include <iostream>
void PrintString(const std::string& name) { std::cout << name <<
std::endl; }
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i)
Traverse(argv, PrintString);
}
I'm in a process of writing a small Linux C++ program for discovering
repeaded files over a filesystem. One part of this task is traversing a
directory structure. This is done by the following recursive function.
Since I'd like it to be general enough to handle function pointers and
function objects I've made it a template.
template <typename CallBack>
void Traverse(const std::string& path, CallBack& callback) throw
(PosixError);
This brings an interesting problem: if I make second parameter is const
(and I'd like it to be that way) then:
1) G++ 3.3.6 refuses to compile the program
error: no matching function for call to `Traverse(char*&, void
(&)(const std::string&))'
2) G++ 4.1.1 compiles the program but the callback is never executed
(i.e. no output) if the callback is function. Works fine if given a
function objects.
Is it some kind of compliler issue or maybe a C++ mistake in my code?
TIA, Kyku
Here's the working part of the program:
#include <string>
#include <cstddef>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
class PosixError : public std::exception
{
public:
PosixError() : _M_code(errno), _M_rep(strerror(_M_code)) {}
PosixError(int code) : _M_code(code), _M_rep(strerror(_M_code)) {}
int Code() const { return _M_code; }
const char* what() const throw() { return _M_rep.c_str(); }
~PosixError() throw() {}
private:
int _M_code;
std::string _M_rep;
};
class DirEntry
{
public:
const std::string& Name() { return _M_name; }
operator bool () const { return !_M_name.empty(); }
private:
DirEntry(struct dirent* dent) : _M_name(dent ? dent->d_name : "") {}
std::string _M_name;
friend class DirWalker;
};
class DirWalker
{
public:
DirWalker(const std::string& dirname) throw (PosixError) {
_M_dir = 0;
Open(dirname);
}
~DirWalker() { if (_M_dir != 0) closedir(_M_dir); }
operator bool () const { return _M_dir != 0; }
void Open(const std::string& dirname) throw (PosixError) {
Close();
_M_dir = opendir(dirname.c_str());
if (_M_dir == 0) throw PosixError();
}
void Close() {
if (_M_dir != 0) {
closedir(_M_dir);
_M_dir = 0;
}
}
DirEntry Read() throw(PosixError) {
const char* name;
struct dirent* dent;
do {
errno = 0;
dent = readdir(_M_dir);
if (errno != 0) throw PosixError();
name = dent->d_name;
} while (dent != 0 && name[0] == '.' && (name[1] == '\0' || name[1]
== '.' && name[2] == '\0'));
return DirEntry(dent);
}
private:
DIR* _M_dir;
};
template <typename CallBack>
void Traverse(const std::string& path, CallBack& callback) throw
(PosixError) {
DirWalker dw(path);
while (DirEntry de = dw.Read()) {
try {
struct stat buf;
std::string fullpath = path + '/' + de.Name();
if (stat(fullpath.c_str(), &buf) < 0) throw PosixError();
callback(fullpath);
if (S_ISDIR(buf.st_mode)) Traverse(fullpath, callback);
} catch (PosixError& pe) {
if (pe.Code() == EACCES) continue;
throw;
}
}
}
#include <iostream>
void PrintString(const std::string& name) { std::cout << name <<
std::endl; }
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i)
Traverse(argv, PrintString);
}