views:

53

answers:

2

I currently am adding some features to our logging-library. One of these is the possibility to declare a module-name for a class that automatically gets preprended to any log-messages writing from within that class. However, if no module-name is provided, nothing is prepended. Currently I am using a trait-class that has a static function that returns the name.

template< class T >
struct ModuleNameTrait {
    static std::string Value() { return ""; }
};

template< >
struct ModuleNameTrait< Foo > {
    static std::string Value() { return "Foo"; }
};

This class can be defined using a helper-macro. The drawback is, that the module-name has to be declared outside of the class. I would like this to be possible within the class. Also, I want to be able to remove all logging-code using a preprocessor directive. I know that using SFINAE one can check if a template argument has a certain member, but since other people, that are not as friendly with templates as I am, will have to maintain the code, I am looking for a much simpler solution. If there is none, I will stick with the traits approach.

Thanks in advance!

+2  A: 

I would like this to be possible within the class.

This is not possible with your approach, explicit specializations have to be declared in the namespace of which the template is a member.

You don't say how the actual using code looks like, but you should be able to let name and overload resolution work for you (e.g. from a logging macro):

template<class T> const char* const name(const T&) { return ""; }

class X;
const char* const name(const X&) { return "X"; }

struct X {
    // prints "X"
    void f() { std::cout << name(*this) <<  std::endl; }
};

struct Y {
    static const char* const name(const Y&) { return "Y"; }    
    // prints "Y"
    void f() { std::cout << name(*this) << std::endl; }
};

struct Z {
    // prints ""
    void f() { std::cout << name(*this) << std::endl; }
};

If you want to define name() only in classes and not outside, there is of course no need for templates or overloads:

const char* const name() { return ""; }

struct X {
    static const char* const name() { return "X"; }    
    // prints "X"
    void f() { std::cout << name() << std::endl; }
};

struct Y {
    // prints ""
    void f() { std::cout << name() <<  std::endl; }
};
Georg Fritzsche
This is perfect! Sometimes I don't see the forest for the trees, I was thinking way to complicated. Thank you!
Space_C0wb0y
I know that problem :)
Georg Fritzsche
A: 

I'm not sure how simple the solution should be, here's a very simple one I used a few times.

There is a base class ClassName with something like:

class ClassName
{
    string name;
public:
    ClassName( string strName = "" ) : name(strName)
    {
         if( strName.length() )
               strName += ": ";
    }
    string getName()
    {
        return name;
    }
};
#ifdef _DEBUG
    #define LOG cout << getName() 
#else
    #define LOG cout
#endif

And other class would inherit it, giving its name:

class Session : virtual public ClassName
{
public:
    Session() : ClassName("Session")
    {
    }

    void func()
    {
         LOG << "Some log here" << endl;
    }
};
Dmitry Yudakov
I considered this approach as well, but I discarded it, because it cannot easily be deactivated by a define or preprocessor directive.
Space_C0wb0y
It depends, with few ifdefs you can limit the whole thing to inheritance of an empty class without calling its function at all.
Dmitry Yudakov