2012年7月4日水曜日

printf + std::cout + OutputDebugString


目的

以下の4つの特徴を合わせ持つ関数を設計する。
  • 書式指定が簡潔(printf)
  • 型セーフかつ拡張性がある(std::cout)
  • Visual StudioやDebugViewに出力できる(OutputDebugString)
  • Visual Studioの「出力」ウィンドウ内をダブルクリックするとソースコードの指定行にジャンプする
使い方
桁数など細かいしても簡単。
int w = 1024;
int h = 768;
DLOG("%04d, %04d") % w % h;
文字列だって簡単。
std::string fname = "test.txt";
DLOG("%s") % fname.c_str();
ただし、他の演算子を含む場合は、%演算子の優先順が低いため括弧()が必要になる。
DLOG("%d") % (1+5);
std::coutと同様の機能は全て備えている!cv::Mat_等の出力も簡単。
#include<opencv2/opencv.hpp>
cv::Mat mat = (cv::Mat_<double>(3, 1) <<
 1.0, 2.0, 3.0,
 1.0, 2.0, 3.0,
 1.0, 2.0, 3.0
);
DLOG("\n%s") % mat;
上記の4つの例の出力例。
.\Test.cpp                    (  10) : 12345 TestClass::testFunc 1024, 768
.\Test.cpp                    (  20) : 12345 TestClass::testFunc test.txt
.\Test.cpp                    (  30) : 12345 TestClass::testFunc 
.\Test.cpp                    (  40) : 12345 TestClass::testFunc
[1 2, 3;
 1, 2, 3;
 1, 2, 3]
フォーマットはこの通り。「:」までがVisual Studio特有のフォーマットでこのように出力すると、出力ウィンドウ内の出力行をクリックすると、ソースコードの対応する行にジャンプするようになっている。
ファイル名                    (行番) :スレッド番号 クラス名::関数名 出力

ソースコード

※以下は、このサイトに書かれているかなりの部分を流量している。
http://reindeer7125.blog129.fc2.com/blog-entry-6.html
#include <boost/format.hpp>
#include <string>
#include <iosfwd>
#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/stream.hpp>
#include <windows.h>
 
#define DLOG dbgout() << (boost::format("%-20s(%4d) : %d %s ") \
 % __FILE__ % __LINE__ % GetCurrentThreadId() % __FUNCTION__) << boost::format
 
namespace detail{
inline void output_debug_string( const char *s){
    ::OutputDebugStringA( s);
}
 
inline void output_debug_string( const wchar_t *s){
    ::OutputDebugStringW( s);
}
 
template<class _Ch>
class dbgout_sink
{
    public:
    typedef _Ch char_type;
    typedef boost::iostreams::sink_tag category;

std::streamsize write( const char_type *s, std::streamsize n){
    std::basic_string<char_type> buf( s, n );
    buf += '\n';
    output_debug_string(buf.c_str());
    return n;
}
};
 
template<class _Ch>
class basic_dbgout : public boost::iostreams::stream<detail::dbgout_sink<_Ch> >
{
    public:
    basic_dbgout(): boost::iostreams::stream<detail::dbgout_sink<_Ch> >(dout_sink){}
    private:
    detail::dbgout_sink<_Ch> dout_sink;
};
}//namespace detail
 
typedef detail::basic_dbgout<char> dbgout;
typedef detail::basic_dbgout<wchar_t> wdbgout;
typedef detail::basic_dbgout<TCHAR> tdbgout;