Skip to content

Instantly share code, notes, and snippets.

@uemuraj
Created October 13, 2014 06:36
Show Gist options
  • Save uemuraj/140b716dee3b3d05fe66 to your computer and use it in GitHub Desktop.
Save uemuraj/140b716dee3b3d05fe66 to your computer and use it in GitHub Desktop.
C++ リハビリ勉強中。コンソール出力において属性(文字色や背景色)を指定可能なマニピュレーターを実装してみる。
#pragma once
#include <iostream>
using namespace std;
//
// コンソール出力において属性(文字色や背景色)を指定可能なマニピュレーターを実装します。
//
// put_time() や put_money() のスタイルを真似ています。
//
template <class _Elem> class put_attr_t
{
const _Elem *text;
const int attr;
public:
put_attr_t(const _Elem *t, const int a) : text(t), attr(a)
{
}
basic_ostream<_Elem, char_traits<_Elem>> &put(basic_ostream<_Elem, char_traits<_Elem>> &os) const;
};
const put_attr_t<char> put_attr(const char *text, int attr)
{
return put_attr_t<char>(text, attr);
}
const put_attr_t<wchar_t> put_attr(const wchar_t *text, int attr)
{
return put_attr_t<wchar_t>(text, attr);
}
const put_attr_t<char> put_attr(const string &text, int attr)
{
return put_attr_t<char>(text.c_str(), attr);
}
const put_attr_t<wchar_t> put_attr(const wstring &text, int attr)
{
return put_attr_t<wchar_t>(text.c_str(), attr);
}
template<class _Elem> basic_ostream<_Elem, char_traits<_Elem>> &operator<<(basic_ostream<_Elem, char_traits<_Elem>> &os, const put_attr_t<_Elem> &attr)
{
return attr.put(os);
}
//
// Windows 専用の実装です。 http://msdn.microsoft.com/ja-jp/library/cc429756.aspx を参照してください。
//
#if _WIN32
#include <windows.h>
extern const unsigned long std_out_handle = STD_OUTPUT_HANDLE;
extern const unsigned long std_err_handle = STD_ERROR_HANDLE;
extern const int red = FOREGROUND_INTENSITY | FOREGROUND_RED;
extern const int blue = FOREGROUND_INTENSITY | FOREGROUND_BLUE;
extern const int green = FOREGROUND_INTENSITY | FOREGROUND_GREEN;
class text_attribute
{
HANDLE hConsoleOutput;
CONSOLE_SCREEN_BUFFER_INFO csbi;
public:
text_attribute(unsigned long out, int attr)
{
if ((hConsoleOutput = ::GetStdHandle(out)) != INVALID_HANDLE_VALUE)
{
if (::GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
{
::SetConsoleTextAttribute(hConsoleOutput, attr & 0xFFFF);
}
else
{
csbi.wAttributes = 0;
}
}
}
~text_attribute()
{
if (hConsoleOutput != INVALID_HANDLE_VALUE && csbi.wAttributes != 0)
{
::SetConsoleTextAttribute(hConsoleOutput, csbi.wAttributes);
}
}
};
#endif
//
// 汎用になりそうなテンプレート部分です。とりあえず、この段階で cout, cerr, wcout, wcerr を見ています。
//
template <class _Elem> basic_ostream<_Elem, char_traits<_Elem>> &put_attr_t<_Elem>::put(basic_ostream<_Elem, char_traits<_Elem>> &os) const
{
if (os == cout || os == wcout)
{
text_attribute attribute(std_out_handle, attr);
return os << text;
}
if (os == cerr || os == wcerr)
{
text_attribute attribute(std_err_handle, attr);
return os << text;
}
return os << text;
}
@uemuraj
Copy link
Author

uemuraj commented Oct 13, 2014

こんな感じで使えるはず。

#include <iostream>

#include "put_attr.h"

using namespace std;

int main() 
{
    // "const char *" を cout へ出力
    cout << "testing" << put_attr(" testing ", red) << "testing" << endl;
    cout << "testing" << put_attr(" testing ", blue) << "testing" << endl;
    cout << "testing" << put_attr(" testing ", green) << "testing" << endl;

    // "const wchar_t *" を wcout へ出力
    wcout << "testing" << put_attr(L" testing ", red) << "testing" << endl;
    wcout << "testing" << put_attr(L" testing ", blue) << "testing" << endl;
    wcout << "testing" << put_attr(L" testing ", green) << "testing" << endl;

    // std::string を cout へ出力
    string testing = " testing ";
    cout << "testing" << put_attr(testing, red) << "testing" << endl;
    cout << "testing" << put_attr(testing, blue) << "testing" << endl;
    cout << "testing" << put_attr(testing, green) << "testing" << endl;

    // std::wstring を wcout へ出力
    wstring wtesting = L" testing ";
    wcout << "testing" << put_attr(wtesting, red) << "testing" << endl;
    wcout << "testing" << put_attr(wtesting, blue) << "testing" << endl;
    wcout << "testing" << put_attr(wtesting, green) << "testing" << endl;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment