代码之家  ›  专栏  ›  技术社区  ›  rubenvb

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

  •  3
  • rubenvb  · 技术社区  · 14 年前

    我正在尝试创建一个简单的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
    

    我想A nullstream -对于发布模式来说,最好是这样定义:

    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)”中:在“;”标记之前需要主表达式(指向行 std::cout << T; )

    在函数“int main(int,char**,char**)”中:标记“<<”之前需要非限定ID

    我相信这很简单,但是我找到的所有模板信息都没有。谢谢你的帮助!

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

    7 回复  |  直到 14 年前
        1
  •  6
  •   Puppy    14 年前

    nullstream类没有整型构造函数。这意味着当您定义debug nullstream时,编译器无法识别没有意义的debug(0)。调试不是接受参数的宏,如果用nullstream替换,nullstream没有接受参数的构造函数。#用这种方式定义是错的。你应该有这样的东西:

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

    现在,您的类在任何环境中的外观和行为都是一样的,但只有在定义了调试的情况下才会输出。我还修复了您试图输出类型的错误。

        2
  •  5
  •   Loki Astari    14 年前

    其他人指出了正常物体的错误。

    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;
    }
    
        3
  •  2
  •   Andre Holzner    14 年前

    你应该写些像

    operator<<(const T &t)
    

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

        4
  •  2
  •   user405725    14 年前

    错误在这里:

    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;
    }
    
        5
  •  1
  •   David Seiler    14 年前
    template<typename T>
    Debug& operator<<( T )
    

    此签名错误;您的参数类型 << 但不是它的名字。然后您将要使用变量名而不是 T 在里面 std::cout << T;

        6
  •  0
  •   Jerry Coffin    14 年前

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

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

        7
  •  0
  •   Paul Michalik    14 年前

    …这将导致L/R值问题。只要跟随 std::cout 模式,如果需要全局调试输出对象。否则,说:

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