繁体   English   中英

带有模板化运算符的条件调试输出类<

[英]conditional debug output class with templated operator<<

我正在尝试创建一个简单的类似qDebug的类,我可以用来在调试模式下输出调试消息,这取决于调用应用程序时传递的一些调试级别。 我喜欢QDebug类的易用性(它可以用作std :: cerr,并且在发布模式下编译时会消失)。 到目前为止我有这个:

#ifdef DEBUG
    static int CAKE_DebugLevel;

    class Debug
    {
        Debug( int level ) : m_output( level <= CAKE_DebugLevel ) {}

        template<typename T>
        Debug& operator<<( T )
        {
            if( m_output )
            {
                std::cout << T;
                return *this;
            }
            else
                return *this;
        }
    private:
        bool m_output;
    };
#else // release mode compile
    #define Debug nullstream
#endif // DEBUG

我认为nullstream -kind of thing对于发布模式定义最好:

class nullstream{};

template <typename T>
nullstream& operator<<(nullstream& ns, T)
{
    return ns;
}

主要是我暂时:

#include "Debug.h"

#include <iostream>

int main()
{
    Debug(0) << "Running debug version of CAKE." << std::endl;
}

这与gcc 4.5.1给出以下错误:

在成员函数'Debug&CAKE_Debug :: operator <<(T)'中:在';'之前的预期primary-expression token(指向std::cout << T;

在函数'int main(int,char **,char **)'中:在'<<'标记之前的预期unqualified-id

我确信它很简单,但我发现的所有常规模板信息都没有。 谢谢你的帮助!

如果您需要更多信息,请询问。

你的nullstream类没有整数构造函数。 这意味着当你#define Debug nullstream时,编译器无法识别Debug(0) - 这没有任何意义。 Debug不是一个接受参数的宏,如果用nullstream替换,则nullstream没有带参数的构造函数。 用这种方式#define是错的哦。 你应该有这样的东西:

#ifdef _DEBUG
static int CAKE_Debuglevel;
#endif

class Debug
{
    Debug( int level ) 
#ifdef _DEBUG
    : m_output( level <= CAKE_DebugLevel ) 
#endif
        {}

    template<typename T>
    Debug& operator<<( T t)
    {
        #ifdef _DEBUG
        if( m_output )
        {
            std::cout << t;
            return *this;
        }
        else
        #endif
            return *this;
    }
private:
#ifdef _DEBUG
    bool m_output;
#endif
};

现在,您的类在任何环境中都会看起来和行为相同,但只有在定义了_DEBUG时才输出。 我还修复了你试图输出类型的bug。

其他人指出了普通物体的错误。

template<typename T> 
Debug& operator<<(T const& value)
{
    if ( m_output )  
    {  
        std::cout << value;  
    }  
    return *this;  
}

但是你还需要一种输出std :: endl和其他操纵器的方法。 由于上面的模板将无法正确处理这些。 为此,您需要一个操作符来处理操作流的函子(即所有的iomanipulator(如std :: endl))。

// Use a typedef to make the code readable.
// This is a function pointer that takes a stream as input and returns the stream.
// This covers functions like std::endl
typedef std::ostream& (*STRFUNC)(std::ostream&);

D& operator<<(STRFUNC func)  // Inside the class
{
    if ( m_output )  
    {  
        // Apply the function
        func(std::cout);
    }
    // But return the debug object
    return *this;
}

处理普通和广泛流的实现:

#include <iostream>

#if defined(_DEBUG)
#define DEBUG_LOG_TEST_CONDITION        output
#define DEBUG_LOG_DEBUG_TEST_LEVEL(v)   (v) <= DebugCake::DebugLevel
#else
#define DEBUG_LOG_TEST_CONDITION        false
#define DEBUG_LOG_DEBUG_TEST_LEVEL(v)   false
#endif

template<typename C,typename T = std::char_traits<C> >
struct DInfo
{
    typedef std::basic_ostream<C,T>& (*StrFunc)(std::basic_ostream<C,T>&);
    static std::basic_ostream<C,T>& getDefault();
};

struct DebugCake
{
    static int DebugLevel;
};
template<typename C,typename T = std::char_traits<C> >
struct D
{

    D(int level)
        :stream(DInfo<C,T>::getDefault())
        ,output( DEBUG_LOG_DEBUG_TEST_LEVEL(level) )
    {}
    D(int level, std::basic_ostream<C,T>& s)
        :stream(s)
        ,output( DEBUG_LOG_DEBUG_TEST_LEVEL(level) )
    {}

    template<typename V>
    D& operator<<(V const& value)
    {
        // In release this is optimised away as it is always false
        if (DEBUG_LOG_TEST_CONDITION)
        {
            stream << value;
        }
        return *this;
    }

    D& operator<<(typename DInfo<C,T>::StrFunc func)
    {
        // In release this is optimised away as it is always false
        if (DEBUG_LOG_TEST_CONDITION)
        {
            func(stream);
        }
        return *this;
    }
    private:
       std::basic_ostream<C,T>&  stream;
       bool                      output;

};

template<>
std::ostream&  DInfo<char,std::char_traits<char>       >::getDefault()
{return std::cout; }

template<>
std::wostream& DInfo<wchar_t,std::char_traits<wchar_t> >::getDefault()
{return std::wcout; }

typedef D<char>    Debug;
typedef D<wchar_t> WDebug;
int DebugCake::DebugLevel = 4;


int main()
{
    Debug   debug(1);

    debug << "Plop" << std::endl;

    WDebug  debugWide(2);
    debugWide << L"WIDE" << std::endl;
}

你应该写类似的东西

operator<<(const T &t)

并在此方法中使用t而不是T (这是类型)。

错误在这里:

template<typename T>
Debug& operator<<( T )
{
    if ( m_output )
    {
        std::cout << T;
        return *this;
    }
    else
        return *this;
}

您不能输出类型,您必须输出一个对象。 正确的代码:

template<typename T>
Debug& operator<<( T value)
{
    if ( m_output )
    {
        std::cout << value;
    }
    return *this;
}
template<typename T>
Debug& operator<<( T )

这个签名是错的; 你有一个<<的参数类型,但不是它的名字。 然后,您需要使用的,而不是变量名Tstd::cout << T;

使用cout << T;的问题cout << T; 已经被指出(你需要提供一个对象实例,而T是一个类型)。

当你修复它时,你将遇到至少一个问题: Debug(0)创建一个临时对象。 要将其作为参数传递给nullstream operator<< ,它需要采用nullstream const &而不是nullstream &作为其参数。

...这将导致l / rvalue问题。 如果你想要一个全局的Debug输出对象,只需遵循std::cout模式。 否则,说:

Debug tDbg(tLevel);
tDbg << "Message" << std::endl;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM