0

I'm creating a small logging class that allows a printf-like syntax (courtesy boost::format) using template functions to implement variable-length parameter lists. I think I'm close: after instantiating a Log object 'logger', I want to be able to write logger.Print("This %s is a %s", some_obj, another_obj);. The way I currently have it, this produces the error "No member named 'Print' in 'Log'".

Can anyone suggest what I need to change?

Log.h:

#ifndef LOG_H
#define LOG_H
#include <string>
using std::string;

#include <sstream>
#include <ostream>
#include <fstream>
#include <boost/format.hpp>

enum Severity {
    DEBUG,
    INFO,
    WARN,
    CRIT,
    DIE,
    LEVELS      // always last; holds # of severity levels
};


class Log {

public:
    Log();
    Log(const char*, const char*);

    void Print_r(int, const boost::format& );

private:
    static const char * sev_code[];

    // order is important here!
    std::ofstream  output_file_stream; // this must be initialized ..
    std::ostream&  output_stream;      // .. before this is bound.
};

int LEVEL; // (where does this belong?)

// This unpacks the variadic arguments one at a time recursively
template <typename T, typename... Params>
    void Print_r (int severity, boost::format &boost_format, const T &arg, const Params&... parameters) {
    Print_r(severity, boost_format % arg, parameters...); // recursively unpack
}

// This checks severity and converts pat to boost::format
template <typename... Params>
void Print (int severity, const string &pat, const Params&... parameters) {
    if (severity < LEVEL) return;
    boost::format boost_format(pat);
    Print_r(severity, boost_format, parameters...);
}

#endif

Log.cpp:

#include "Log.h"
#include <iostream>
using std::cout;
using std::endl;

#include <string>
using std::string;

#include <fstream>

const char * Log::sev_code[] = { 
    "DBUG",
    "INFO",
    "WARN",
    "CRIT",
    "DIE "
};

// Constructor w/no parms = logging to cout
Log::Log() :
    output_stream(cout) {

}

// Constructor w/parms = logging to file
Log::Log(const char* dir, const char* file) :
    output_stream(output_file_stream) {

    string output_file_name = string(dir) + "/" + string(file);
    output_file_stream.open(output_file_name.c_str(), std::ofstream::out);
}

// This does the actual logging of the formatted message to the
// output_stream:
void 
Log::Print_r (int severity, const boost::format &boost_format) {
    std::stringstream s;
    s << "[" << sev_code[severity] << "] "
      << boost_format;
    output_stream << s << endl;
}
Chap
  • 3,649
  • 2
  • 46
  • 84

1 Answers1

0

From this code the Print template is outside of the Log class. You need to move it inside the class definition.

bruvel
  • 396
  • 2
  • 6
  • Yes, that was the problem. I was somewhat confused about the relationship between template functions and member functions. Apparently these are orthogonal. – Chap Sep 02 '13 at 03:39