Windowsのgvim用にRictyを作るのが面倒だったので
http://www.levien.com/type/myfonts/inconsolata.htmlからInconsolata
http://mix-mplus-ipa.sourceforge.jp/からMigu 1M
をダウンロードしてインストールする。
.gvimrcに
set guifont=Inconsolata:h12 set guifontwide=Migu_1M:h12
と書き込む。
あとはgdi++とかMacTypeとかで適当に綺麗にすればOK。
Boostで抽象構文木を作ってllvm言語に変換してみた
X11 extensionsのXRandRでディスプレイの名前と使用できる解像度とリフレッシュレートを取得してみる
man見たりしたけど、XRRScreenResourcesとかが見当たらなかったのでX11/extension/Xrandr.hの転載をのせつつメモ。
XRandRのバージョンが1.2以上なら使えるはずです。
準備
以下のヘッダをインクルードします。
#include <X11/extension/Xrandr.h>
まずXRRGetScreenResourcesを使って、XRRScreenResourcesのポインタを取得します。XRRScreenResoucesのoutputsはディスプレイの数だけ要素があるRROutputの配列で、要素数はnoutputに格納されています。RROutputはXIDのtypedefです。使い終わったらXRRFreeScreenResourcesで解放しましょう。
typedef struct _XRRScreenResources { Time timestamp; Time configTimestamp; int ncrtc; RRCrtc *crtcs; int noutput; RROutput *outputs; int nmode; XRRModeInfo *modes; } XRRScreenResources; XRRScreenResources * XRRGetScreenResources (Display *dpy, Window window); void XRRFreeScreenResources (XRRScreenResources *resources);
名前の取得
ディスプレイの名前を取得するにはXRRGetOutputInfoを使ってXRROutputInfoのポインタを取得します。XRROutputInfoのnameに名前の文字列、nameLenにその文字列の長さが格納されています。使い終わったらXRRFreeOutputInfoで解放しましょう。
typedef struct _XRROutputInfo { Time timestamp; RRCrtc crtc; char *name; int nameLen; unsigned long mm_width; unsigned long mm_height; Connection connection; SubpixelOrder subpixel_order; int ncrtc; RRCrtc *crtcs; int nclone; RROutput *clones; int nmode; int npreferred; RRMode *modes; } XRROutputInfo; XRROutputInfo * XRRGetOutputInfo (Display *dpy, XRRScreenResources *resources, RROutput output); void XRRFreeOutputInfo (XRROutputInfo *outputInfo);
解像度とリフレッシュレートの取得
XRRScreenResourcesのメンバにmodesというのがあって、XRRModeInfoの配列になっています。その要素数はXRRScreenResourcesのnmodeです。解像度はXRRModeInfoのwidthとheightに格納されています。
typedef unsigned long XRRModeFlags; typedef struct _XRRModeInfo { RRMode id; unsigned int width; unsigned int height; unsigned long dotClock; unsigned int hSyncStart; unsigned int hSyncEnd; unsigned int hTotal; unsigned int hSkew; unsigned int vSyncStart; unsigned int vSyncEnd; unsigned int vTotal; char *name; unsigned int nameLength; XRRModeFlags modeFlags; } XRRModeInfo;
リフレッシュレートはXRRModeInfoを使って求める必要があり、xrandr-1.4のソースの540行目以降からパクったを参考にした実装例は以下のようになります。一応C++です。
double mode_refresh(XRRModeInfo const& info) { auto v_total = info.vTotal; if( info.modeFlags & RR_DoubleScan ) { v_total *= 2; } if( info.modeFlags & RR_Interlace ) { v_total /= 2; } return info.hTotal && v_total ? static_cast< double >( info.dotClock ) / ( static_cast< double >( info.hTotal ) * v_total ) : 0; }
例
実装例で一応C++です。本当はXRRQueryVersionなどを使ってXRandRを使っているかどうかやバージョンを調べる必要とかありますが面倒なので省略。mode_refreshは上の方を見てください。
int main() { Display* disp = XOpenDisplay( nullptr ); auto res = XRRGetScreenResources( disp, XRootWindow( disp, DefaultScreen( disp ) ) ); for( int i = 0; i < res->noutput; ++i ) { // 名前の表示 auto info = XRRGetOutputInfo( disp, res, res->outputs[i] ); std::cout << std::string( info->name, info->nameLen ) << " : " << std::endl; // 使える解像度とリフレッシュレートを列挙 for( int j = 0; j < res->nmode; ++j ) { std::cout << " " << res->modes[j].width << "x" << res->modes[j].height << "-" << mode_refresh( res->modes[j] ) << std::endl; } XRRFreeOutputInfo( info ); } XRRFreeScreenResources( res ); XCloseDisplay( disp ); }
BOOST_USE_WINDOWS_H
windows.hとBoost.Chronoを同時に使うとboost/detail/winのファイルで次のような警告が出ることがあります。(以下の警告はgccのものです。)
warning: declaration of 'void boost::detail::win32::GetSystemTimeAsFileTime(boost::detail::win32::FILETIME_*)' with C language linkage warning: conflicts with previous declaration 'void boost::date_time::winapi::GetSystemTimeAsFileTime(boost::date_time::winapi::FILETIME*)
ちなみに出てくるときは複数の警告でGetSystemTimeAsFileTimeだけではないはずです。
この警告を出さないようにするにはBoost.Chronoのヘッダをインクルードする前に
#define BOOST_USE_WINDOWS_H
を書きます。
-DBOOST_USE_WINDOWS_H
と書いてもいけるはずです。
DirectInputのSetCooperativeLevelにNULLポインタ
IDirectInputDevice8::SetCooperativeLevelについて。
(日本語)http://msdn.microsoft.com/ja-jp/library/bb205980(v=vs.85).aspx
(英語)http://msdn.microsoft.com/en-us/library/microsoft.directx_sdk.idirectinputdevice8.idirectinputdevice8.setcooperativelevel(v=vs.85).aspx
MSDNには第1引数のHWNDにトップレベルのウィンドウのハンドルを要求すると書かれていますが、第2引数のDWORDを以下の通り渡すと第1引数がNULLポインタでもエラーを出さずに通すことができます。
DISCL_BACKGROUND | DISCL_NONEXCLUSIVE
これでウィンドウなしにデバイスのデータを取ることが出来ました。
ウィンドウはいらないけどゲームパッドの入力が欲しい時には使えそうですが、MSDNにNULLポインタを渡した場合どうなるかというのは見当たらなかったのでごにょごにょ・・・。
ちなみに、第1引数をNULLポインタにして第2引数に
DISCL_BACKGROUND | DISCL_EXCLUSIVE DISCL_FOREGROUND | DISCL_EXCLUSIVE DISCL_FOREGROUND | DISCL_NONEXCLUSIVE
などを渡すと戻り値でE_HANDLEを返してきてエラーとなります。
OpenGLのVSync待ち
OpenGLでVSyncを待つようにをするには、wgl(Windows)ではwglSwapIntervalEXT関数、glX(X11)ではglXSwapIntervalEXT関数またはglXSwapIntervalSGI関数を使います。しかし、これらは拡張関数なので対応しているかどうかを調べたほうが良いでしょう。
拡張に対応しているかどうかを調べる
wglの場合
GLubyte const* glGetString(GLenum); // glGetString( GL_EXTENSIONS )のようにして呼び出すだけ
glGetStringにGL_EXTENSIONSを渡して文字列を取得します。
char const* wglGetExtensionsStringEXT(); char const* wglGetExtensionsStringARB(HDC);
これらの関数も呼び出してそれぞれ文字列を取得しますが、この2つの関数自体も拡張関数なのでwglGetProcAddress関数を使ってアドレスを取得しましょう。
そして、wglSwapIntervalEXT関数を使いたい場合、取得したいずれかの文字列の中に次の文字列がないといけません。
"WGL_EXT_swap_control"
あればwglSwapIntervalEXT関数を使うことができます。
glXの場合
GLubyte const* glGetString(GLenum); // glGetString( GL_EXTENSIONS )のようにして呼び出すだけ
glGetStringにGL_EXTENSIONSを渡して文字列を取得します。
char const* glXGetClientString(Display*, GLenum name); // GLenum nameにGLX_EXTENSIONSを渡す char const* glXQueryExtensionsString(Display*, int screen);
これらの関数も呼び出して文字列を取得します。この時、glXGetClientString関数のGLenum nameにGLX_EXTENSIONSを渡すと対応している拡張の文字列が得られます。また、これらは拡張関数ではないのでそのまま呼び出すことができます。
そして、glXSwapIntervalEXT関数またはglXSwapIntervalSGI関数を使いたい場合、取得したいずれかの文字列の中に次のいずれかの文字列がないといけません。
"GLX_EXT_swap_control" "GLX_SGI_swap_control"
GLX_EXT_swap_controlがあればglXSwapIntervalEXT関数、
GLX_SGI_swap_controlがあればglXSwapIntervalSGI関数が使えます。
SwapInterval
wglの場合は、
BOOL wglSwapIntervalEXT(int interval);
となっており、wglGetProcAddress関数を使ってこの関数のアドレスを取得して使用できます。
glXの場合は、
void glXSwapIntervalEXT(Display*, GLXDrawable, int interval); int glXSwapIntervalSGI(int interval);
のいずれかで、対応している関数をglXGetProcAddress関数を使ってアドレスを取得して使用できます。
いずれの関数においてもint intervalがVSyncを何回待つかを決めるための引数です。例えば、int intervalに0を渡すとVSyncを待たず、1を渡すとVSyncを1回待つ。2を渡すとVSyncを2回待つようになります。
SwapIntervalやそれぞれの関数の詳細については以下を参照のこと。
http://www.opengl.org/wiki/Swap_Interval
http://www.opengl.org/registry/specs/EXT/wgl_swap_control.txt
http://www.opengl.org/registry/specs/SGI/swap_control.txt
http://www.opengl.org/registry/specs/EXT/swap_control.txt
http://msdn.microsoft.com/ja-jp/library/windows/desktop/dd374386(v=vs.85).aspx
http://www.opengl.org/sdk/docs/man2/xhtml/glXGetProcAddress.xml
http://www.opengl.org/wiki/GLAPI/glGetString
http://www.opengl.org/registry/specs/EXT/wgl_extensions_string.txt
http://www.opengl.org/registry/specs/ARB/wgl_extensions_string.txt
http://www.opengl.org/sdk/docs/man2/xhtml/glXGetClientString.xml
http://www.opengl.org/sdk/docs/man2/xhtml/glXQueryExtensionsString.xml
いまさらVariadic Templatesをまとめてみる
この記事はC++ Advent Calendar 2012の13日目です。
Variadic Templatesとは
C++11ではテンプレートで"."を3つ付けることが出来るようになりました、
こんな感じで。
template <class... Ts>
これで何が出来るのかというと、0個以上の任意のテンプレート引数を受け取れるようになります。このとき、Tsをテンプレートパックと呼びます。
Variadic Templateはテンプレートクラスと関数テンプレートの両方で使うことが出来ます。
- テンプレートクラスの場合
template <class... Ts> class hoge;
このように書かかれていれば、
hoge<> hoge< long > hoge< int, short >
こんな感じで型を渡すことができるようになります。
また、class...のように型だけでなくint...のような整数を取る事もできて、
template <int... Values> class huga;
のように書かれていれば、
huga<> huga< 128 > huga< 2, 42 >
こういう風に渡すことができます。
- テンプレート関数の場合
template <class... Ts> T foo(Ts... args) // ここでのTは任意の戻り値の型
テンプレート関数で使うと、任意の型で任意の数の引数を取ることが出来るようになります。
例えば、
int i; double d; std::string str; foo( i, d, str );
と、こんな事が出来るようになります。
テンプレートパックの展開
- テンプレートパックの型を展開
テンプレート引数にclass... Tsがあって、別のテンプレート引数を持つクラスや関数などに渡すときはTs...のように"..."をつけます。テンプレートパックの最初の要素の型を返すメタ関数headとVariadic Templatesだけの関数hogeを例にします。
// using typedefはC++11で導入されたもので、 // typedef A B;の代わりにusing B = A;と書けます。 // 詳しくはググってね。 template <class T, class... Rest> struct head { using type = T; }; template <class... Ts> struct hoge { using type = typename head< Ts... >::type; };
hogeのTs...の最初の要素がheadのTに渡され、残りがRest...に渡されます。
テンプレートパックを展開するときに別のテンプレートクラス等を適用することもできます。
template <class... Ts> struct type_list; template <class T> struct a_t; template <class... Ts> struct hoge { using type = type_list< a_t< Ts >... >; };
としたとき、
std::is_same< typename hoge< int, short >::type, type_list< a_t< int >, a_t< short > > >::value;
これがtrueになります。
hogeのtypeがtype_list< a_t< Tsの1つ目の要素の型 >, a_t< Tsの2つ目の要素の型 > >となっていて、a_t< Ts >...がどう展開されるのかがわかると思います。
- テンプレートパックの値を展開
C言語の可変長引数とは違って、va_listのようなマクロは必要ありません。
テンプレート引数にclass... Ts、関数の引数にTs... argsがあって、別の関数に渡すときはargs...と引数名のほうに"..."をつけます。テンプレートパックの最初の要素の値を返す関数headとVariadic Templatesだけの関数fooを例にします。
template <class T, class... Rest> T head(T value, Rest...) { return value; } // C++11で導入された戻り値の型の後置とdecltypeを知らない場合はググってね template <class... Ts> auto foo(Ts... args) -> decltype( head( args... ) ) { return head( args... ); }
fooからheadが呼び出され、argsの最初の要素がT valueに渡され、残りはRest...に渡されます。
もちろん既存の関数にテンプレートパックを展開して呼び出すことは可能です。
ただし、テンプレートパックの要素の数と既存の関数の引数の数が一致していることと、テンプレートパックの要素の型と引数の型が一致しているか変換可能でなければなりません。
以下にstd::sqrtを用いた例を示します。
#include <cmath> template <class... Ts> double sqrt_ts(Ts... args) { return std::sqrt( args... ); } int main() { sqrt_ts( 4.0 ); // OK sqrt_ts( 4.0, 9.0 ); // NG 数が合ってない sqrt_ts( "done-n" ); // NG std::sqrtの引数の型と合ってない }
テンプレートパックを展開するとき、要素ごとに別の関数を適用することも可能です。
int plus1(int x) { return x + 1; } template <class... Ts> void func(Ts... args) { // printはうまく全部出力してくれる関数 print( plus1( args )... ); }
このとき、func( 2, 4, 8 );と呼びだすと、func内のplus1( args )...はplus1( 2 ), plus1( 4 ), plus1( 8 )とほぼ一緒となります。plus1(argsの1つ目の要素の値), plus1(argsの2つ目の要素の値), plus1(argsの3つ目の要素の値)という風になっていますね。
さらにテンプレート関数を要素ごとに適用することも可能です。
template <class... Ts> auto func(Ts... args) -> decltype( f( std::forward< Ts >( args )... ) ) { // 打つのが面倒なのでfは適当に定義された関数 return f( std::forward< Ts >( args )... ); }
std::forward<argsの1つ目の要素の型>( argsの1つ目の要素の値 ), std::forward<argsの2つ目の要素の型>( argsの2つ目の要素の値 ),・・・とTsとargsが要素ごとにちゃんと展開されて渡されます。
テンプレートパックの要素の数の取得
sizeof...演算子を用いてテンプレートパックの要素の数を取得できます。
template <class... Ts> class foo { static constexpr std::size_t value = sizeof...( Ts ); }; template <class... Ts> void f(Ts... args) { // sizeof演算子と同様に型でも引数名でも sizeof...( Ts ); sizeof...( args ); }
テンプレート・テンプレート・パラメータでVariadic Template
template <template <class...> class T> struct hoge;
これができます。
Tには、Variadic Templateではないテンプレートクラスを渡すことも可能です。
以下の例では、fooの特殊化でVariadic Templatesなテンプレート・テンプレート・パラメータを用いています。テンプレートクラスならtrue_type、でなければfalse_typeとなります。
#include <iostream> #include <type_traits> template <class T> struct foo : public std::false_type { }; template <template <class...> class T, class... Ts> struct foo< T< Ts... > > : public std::true_type { }; template <class... Args> struct a_t; template <class T> struct b_t; int main() { std::cout << std::boolalpha << foo< int >::value << std::endl; // false std::cout << std::boolalpha << foo< a_t< int, short > >::value << std::endl; // true std::cout << std::boolalpha << foo< b_t< double > >::value << std::endl; // true }
テンプレートパックの要素を順番に処理する
- 関数の再帰でテンプレートパックの要素の値を順番に
テンプレートパックの要素を順番に処理したいときにどうするかを、
まず以下に示すテンプレートパックの要素の値を順番に足していった合計を返すsum関数を例にして説明します。
#include <iostream> int sum_impl(int result) { return result; } template <class T, class... Rest> int sum_impl(int result, T value, Rest... rest) { return sum_impl( result + value, rest... ); } template <class... Ts> int sum(Ts... args) { return sum_impl( 0, args... ); } int main() { std::cout << sum( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ) << std::endl; // 55 }
実際の主役はsum_impl関数です。
再帰を使ってsum関数からresultに0を、argsをsum_impl関数に渡してargsの最初の要素をvalueに渡して、残りをrestに渡します。次に、resultにvalueを足したものを次のsum_impl関数のresultに渡し、rest...でテンプレートパックを展開してrestの最初の要素を次のsum_impl関数のvalueに、restの残りを次のsum_impl関数のrestに渡します。こうすることでsum_impl関数を呼び出すたびにrestの要素が1つずつ減っていき、最終的になくなります。なくなったら上から2番目のsum_impl関数のT valueに入るものはなくなって呼び出せないので、一番上のsum_impl関数が呼び出されて合計を返します。
このように再帰を使うことでテンプレートパックの要素の値を順番に処理することができます。
- 型だけを順番に
Targetで指定した型と一致する型がいくつTsにあるかをstd::integral_constantで返すcountメタ関数を例に。
#include <type_traits> #include <iostream> template <std::size_t Result, class Target, class... Ts> struct count_impl; template <std::size_t Result, class Target, class T, class... Rest> struct count_impl< Result, Target, T, Rest... > { using type = typename count_impl< Result, Target, Rest... >::type; }; template <std::size_t Result, class Target, class... Rest> struct count_impl< Result, Target, Target, Rest... > { using type = typename count_impl< Result + 1, Target, Rest... >::type; }; template <std::size_t Result, class Target> struct count_impl< Result, Target > { using type = std::integral_constant< std::size_t, Result >; }; template <class Target, class... Ts> struct count { using type = typename count_impl< 0, Target, Ts... >::type; }; int main() { // intがいくつあるか std::cout << count< int, int, short, int, long, int, int, int >::type::value << std::endl; // 5 }
上から2番目のcount_implはTargetと残りのテンプレートパックの最初の要素が一致しないとき、上から3番目のcount_implは一致したとき、上から4番目のcount_implはテンプレートパックの要素がなくなったときを特殊化していて、count_implの内部でcount_impl::typeすることで再帰になって順番に処理できます。
テンプレートパックの要素をインデックスで
Variadic Templatesを使っているとインデックスでアクセスしたいと思うようになるはずです。
- 型
型のリストからインデックスで型を取得するというのは、Boost.MPLのatやat_cが有名ですし、Variadic TemplatesのテンプレートパックをBoost.MPLのコンテナに突っ込めるようにすればBoost.MPLが利用できます。
しかし、ここではあえて自分で作ってみます。
at_cはTsのIndexに指定したインデックスにある型をat_c::typeで返します。
#include <type_traits> #include <iostream> template <std::size_t Index, std::size_t I, class... Ts> struct at_c_impl; template <std::size_t Index, std::size_t I, class T, class... Rest> struct at_c_impl< Index, I, T, Rest... > { using type = typename at_c_impl< Index, I + 1, Rest... >::type; }; template <std::size_t Index, class T, class... Rest> struct at_c_impl< Index, Index, T, Rest... > { using type = T; }; template <std::size_t Index, class... Ts> struct at_c { using type = typename at_c_impl< Index, 0, Ts... >::type; }; int main() { static_assert( std::is_same< at_c< 2, int, short, long, float, double >::type, long >::value, "" ); }
at_c_implを再帰することでIndexと一致するまでIを1ずつ増やして、Restを1つずつ減らしていくことで実現しています。
もしIndexがTs...の範囲を超えていたらコンパイルエラーとなります。コンパイルエラーにしたくなければ、次のような特殊化を加えれば良いでしょう。
struct null_type; template <std::size_t Index, std::size_t I> struct at_c_impl< Index, I > { using type = null_type; };
null_typeは型がないというのを表すために適当に作った型です。
- 値
テンプレートパックの要素の値をインデックスで取得してみましょう。
簡単にするためにTsの要素にはint型の値しかないということにします。
get関数はargsのインデックスnにある値を返すものです。
指定したインデックスがテンプレートパックの範囲を超えていた場合は0を返すとします。
#include <iostream> int get_impl(std::size_t, std::size_t) { return 0; } template <class... Ts> int get_impl(std::size_t n, std::size_t i, int value, Ts... rest) { return n == i ? value : get_impl( n, i + 1, rest... ); } template <class... Ts> int get(std::size_t n, Ts... args) { return get_impl( n, 0, args... ); } int main() { std::cout << get( 2, 2, 4, 6, 8, 10 ) << std::endl; // 6 }
型の場合と同じく、再帰でnと一致するまでiを1ずつ増やして、restを1つずつ減らしていくことで実現しています。
おわりに
だらだらとVariadic Templatesの説明を行って来ました。
一応Variadic Templatesの基礎の部分は網羅しているはずです。
Variadic Templatesを知っている人は面白くない内容だったと思いますが、私は謝らない。再確認ぐらいに使ってあげてください。
インデックスアクセスの例では直接Variadic Templatesを使っていますが、
at_c< type_list< int, short, long >, 1 >::type // short
のようにインデックスを後ろにしたり別のテンプレートクラスを使って使いやすくするなどの改良が考えられますし、
これに限らずご自身でいろいろお試しください。