help-gplusplus
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

const callback


From: Kyku
Subject: const callback
Date: 20 Aug 2006 04:10:24 -0700
User-agent: G2/0.2

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

Update: prefixing Traverse argument with & solves the problem in both
g++3 and 4. But then I always thought Function name on its own is
equivalent to its adress.

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[i], PrintString);
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]