【问题标题】:Declare module name of classes for logging声明用于记录的类的模块名称
【发布时间】:2010-03-25 09:43:19
【问题描述】:

我目前正在向我们的日志库添加一些功能。其中之一是可以为一个类声明一个模块名,该类会自动预先添加到从该类中写入的任何日志消息中。但是,如果没有提供模块名称,则不会添加任何内容。目前我正在使用一个具有返回名称的静态函数的特征类。

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

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

这个类可以使用辅助宏来定义。缺点是模块名称必须在类之外声明。我希望这在课堂上是可能的。此外,我希望能够使用预处理器指令删除所有日志记录代码。我知道使用 SFINAE 可以检查模板参数是否具有某个成员,但由于其他人对模板不像我那么友好,因此必须维护代码,我正在寻找一种更简单的解决方案。如果没有,我会坚持使用特质方法。

提前致谢!

【问题讨论】:

    标签: c++ templates logging traits sfinae


    【解决方案1】:

    我希望在课堂上可以做到这一点。

    这在您的方法中是不可能的,必须在模板所属的命名空间中声明显式特化。

    您没有说明实际使用代码的样子,但您应该能够让名称和重载解析为您工作(例如,来自日志记录宏):

    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; }
    };
    

    如果你只想在类中而不在外部定义name(),当然不需要模板或重载:

    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; }
    };
    

    【讨论】:

    • 这太完美了!有时我只见树木不见森林,我在想办法变得复杂。谢谢!
    【解决方案2】:

    我不确定解决方案应该有多简单,这是我用过几次的一个非常简单的解决方案。

    有一个基类ClassName,类似于:

    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
    

    其他类会继承它,并给出它的名字:

    class Session : virtual public ClassName
    {
    public:
        Session() : ClassName("Session")
        {
        }
    
        void func()
        {
             LOG << "Some log here" << endl;
        }
    };
    

    【讨论】:

    • 我也考虑过这种方法,但我放弃了它,因为它不容易被定义或预处理器指令停用。
    • 视情况而定,只需很少的 ifdef,您就可以将整个事情限制为空类的继承,而根本不调用它的函数。
    猜你喜欢
    • 2013-03-03
    • 2019-03-21
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 2017-05-05
    • 2021-11-06
    • 2018-10-02
    • 2016-09-06
    相关资源
    最近更新 更多