好きなC++ランキング
好きなだけで使えるとは言っていない所がポイントです。
コンパイラだけでなく、周辺環境も含めて考慮しているのでC++としています。
1位 wandbox + clang/gcc
個人的に新機能を試す時が一番幸福度が高いのでこの組み合わせが好きです。
環境構築が必要なしに新機能を試せるのは本当にありがたいです。好き。
立ち上がる速度、実行までの速度、速度でいえばこれに勝てる構成はないです。好き。
ただ、ファイル数が多かったり、自分の好きなエディタと連携しようと思うと面倒だったりは良くないです。Webサービスである以上は仕方ないのですが。
また、私が愛用しているchromeプラグインVimiumとも相性が悪いです。対象ページでプラグインをオフにするとページ切り替えもたつくし、オンにしていると不意にページを閉じてしまったりで。
後、boostがいまいち使いにくい印象を受けます。コンパイルが必要なライブラリ周りがどうやったら試せるのか分からなかったのかな?
以前、boost/qvmの機能を試そうとした時に上手に解決できませんでした。
2位 Cloud9 + clang/gcc
今はカード登録が必要になった?みたいですが、私は昔っから使っているお陰か登録していないので気軽です。
ようするただのVM環境なのでLinuxでいーじゃん的な意見はもっともなのですが、新機能や新しいことを試す時に一番重視したいのは環境の再構築しやすさなので私的には外せないポイントだったりします。クリーンなLinuxマシーンが1分かからずに作れて、何個でも作って良いとかうおおーってなります。好き。
こちらもテキストエディタ関係でwandboxと同じ悩みを抱えていますが、純粋なvimを使えるのでマシです。ただ、vimで日本語を扱うと表示がバグります。日本語を扱う場合は素直に備え付けのエディタを使わなければなりません。うーむ。
後、私は職業柄GUI関係のコードの実験を行いたいことが多いのですが、そちらの実験ができません。これは仕方ない。
また、無料でつかえるマシンのメモリや処理速度が貧弱なので一部ビルドが辛いです。Railsのinstallにそのままだとコケたりします。無料だとしばらくアクセスしなかったVMにアクセスするのに時間がかかるのも面倒です。しかし、ここらへんはお金で解決できる問題なので仕方ないです。私も使用頻度がもう少し高ければ払っていきたいです。
3位 JetBrains + clang/gcc/VC
この組み合わせは私がヘビーに試せていないだけで1位になるポテンシャルを秘めていると思っています。
私がしっかりと試したのはAndroidStudio + gccだけなのでその知見で書きます。CLionは触るだけしかしていないので、最初のセッティングでvimのキーバインドを選択できたのが感動した程度しか言えないです。
上記2つと比べるとマシンに入れる必要があるので起動時間、アップデート時間、環境汚染等は避けられません。しかし、それを補って余りあるメリットを提供してくれます。
素晴らしいと思うのは、CMake前提のプロジェクト構成をデフォルトで吐き出してくれることです。これならCMakeやMakeの知識がない人でもC++の簡単なプロジェクト管理ができます。しかもツール、環境間の相互運用性も高い。グッジョブですね。
また、テキストエディタとvimのキーバインドの相性も良く特に不満なく使えます。上記2つとは比べものにならない自動補間、自動問題解決を行ってくれます。
最大の問題点。AndroidStudioでのC++はAndroid向けアーキテクチャに対してコンパイルされるので汎用性が低い。CLionは期間限定で無料試用はできるものの有料。
個人的には開発環境が有料というのはちょっと無いので、せめて個人利用の範囲では無料にしてくれるまで押すつもりはないです。個人でがっつり使ってないものを企業で推進するのは難しいと思いますよっと。
4位 VM + clang/gcc
最近のマシンは高性能になってきているのでVMを常時起動してても重さは感じないので素晴らしいですね。
この構成もLinuxで良いじゃねーか案件なんですが、私が常用しているPCはWindowsだし、上記で触れた環境の壊しやすさを考慮するとこの選択になります。
VMには昔はVMwareを使っていたんですが、最近ではVirtualBoxとVagrantで運用していました。
Web環境の際に不満だったGUIの実験ができ、環境的にもただのLinuxなので完璧かのようにみえます。
しかし、やはりVM関係の特定の操作には時間がかかる、複数のVMを管理しているとストレージを圧迫するし簡単に管理できる何かが必要という感じになりました。
それにVM上でIDEまで入れるのなら流石にLinux機で良いと思うので立ち位置が微妙な構成に感じます。
また、これが私にとって一番致命的だった理由なのですが、VMの操作を色々行った後はVirtual Network Bridgeが生成され、それがネトゲのPingに深刻な影響を与えることが時々発生したためです。開発のために日常を犠牲にするなんてあってはならないことです。
5位 VisualStudio + VC
はい、仕事ではもっぱらこれです。
vimキーバインドもプラグインによりほぼ不満なく動作します。その上優秀な補完、定義へのジャンプ、検索、デバッグと至れり尽くせりです。
昔は絶対に使いたくなかったVCですが、VisualStudio2015辺りに付随するVCからしっかりと新しいC++の機能に対応してきてかなり良くなってきています。
また、NuGetによるライブラリ連携も簡単にできるようになっており、テストやboost、OpenCV等を簡単に導入できるもの魅力的です。
しかし、他の構成では扱わない規模のプロジェクトを扱っているので公正な判断とは言いづらいですが、重い、固まるのが最大のデメリットです。
補完や定義へのジャンプを要求したら数十秒返事が返ってこないのが頻発します。やってらんねぇ。
また、ソリューションファイルが扱い辛いです。特定のパスを要求しようと思ったらソリューションファイルに直書きするしかないとかなるんなら、初めから設定ファイルを書けるプロジェクトを生成して欲しい。CMake等でソリューションファイルを生成した方が分かりやすく想定した動作をします。
6位 MinGW (or MinGW-W64), Cygwin + gcc/clang
昔はお世話になったこの構成ですが、VMも走らせることができる今となっては選択しなくても良いのかなと思います。
IDEが内部でこれらを処理してくれるので、自分で触る必要はないと思います。
ただ、MinGWのコマンドは便利なのでC++のコンパイル環境以外としてなら使うべきだと思います。
私はgit bash(gitに最適化されたMinGW環境)でそれらを代用しています。
おまけ vcpkg
GitHub - Microsoft/vcpkg: VC++ Packaging Tool
NuGetの代わりになるかと思いきや管理が大変過ぎて使えない感じになってしまっている惜しいプロジェクト。
各cプロジェクトを依存関係を考慮してビルド、リンクできるようにするパッケージマネージャ。
それだけ聞くと最高な感じだが、実状として各プロジェクトの依存関係やビルドファイルを全部人力で構築しているので対応が遅れるのとバグが取り切れてない。
誰でも編集できるようにすると質の低いビルドファイルが作られるという理由で中央集権化した(NuGetが低質なビルドファイルにより壊れているパッケージが多数あることを受けてかな?)結果役に立たないものになってしまった感じ。
やはり、やるべきは良質なテンプレートの提供とデベロッパーの啓蒙なのだろう。
おまけ Unreal C++
Unreal Engineをビルドする際に使用される特殊加工されたビルド環境です。
Reflectionが使えないC++に無理矢理ではあるもののスマートにReflectionをもたらした事は素晴らしいと思います。関数名やクラス名をそのままエディタ上で扱えることは苦労以上のメリットがあると考えます。
また、モジュールの概念が素晴らしく、これにより明確なスコープの管理と公開範囲の管理、ホットリロード等が実現されます。
このシステムについての不満としてはプリフィックスの強制と使っているコーディング規約、膨大なファイル量による重さがあります。
最後に
では、みなさん。良きC++を。
自分で作ったクラスをrange based forに対応させよう
Range based forは素敵
for(auto value: vector){ }
良いですね、スマートです。
しかし、これstd::vector等のスタンダードライブラリに入っているクラスしか使えないと思ってはいないでしょうか?
私が体験した職場で自身のクラスをrange based forに対応させているパターンを見たことがありません。
案外簡単にできるので是非やってみてください。
最低限必要なこと
struct Iterator{ auto operator!=(Iterator){ return false; } auto operator++(){ } auto operator*(){ return nullptr; } }; struct Foo{ auto begin(){ return Iterator(); } auto end(){ return Iterator(); } }; int main() { Foo foo; for(auto item: foo){ } }
はい、これだけです。
Iteratorに既存のものを利用する場合はなんとbeginとendの関数を定義するだけでrange based forに対応できてしまうのです。
ただ、注意点もあります。
Iterator != Iteratorでループの終了条件を判定するので同じコンテナのIteratorを返すようにしないといけません。
もっと自由度を高くしたい場合は専用のイテレータを作った方が良いでしょう。
後、const版のbeginとendを作っておいた方が後々幸せになれます。
カスタムイテレータ
イテレータの方もそこまで難しいことはなく、range based forの判定に必要な関数を定義するだけです。
operator!=で現在のイテレータとend()のイテレータを比較します。現在のイテレータとend()のイテレータが一致した場合にループ処理を終了させます。
operator++で現在のイテレータを次のイテレータに変換します。
operator*でイテレータからforで使う値を取り出します。
auto item = *iterator;
と同じですね。
展開されるコード
上記クラスがどう処理されるのかも記述しておきます。
for (auto __begin = foo.begin(), __end = foo.end(); __begin != __end; ++__begin ) { auto item = *__begin; // range based forの中身 }
begin(), end(), operator!=, operator++, operator*が何故必要なのか一目でわかりますね。
参考
綺麗にコードを書く技術
概要
難しい処理をこなす処理を簡単に描けるプログラマではそのコードは汚いものです。
思うに綺麗にコードを書くことは技術のレベルとは関係ないので執着されないのでしょう。
しかし、私は綺麗にコードを書くことは無駄には思えません。
技術が技術と呼ばれる理由に人に共有し洗練していくことが可能という部分があると思います。
私の考える綺麗にコードを書く方法を共有することで技術として残せたらと思います。
リネーム程度のリファクタリングは挨拶かのようにする
汚いコードを書く人の特徴として、一度作成し終わった関数やクラスには追加しかしないというものがあります。
作成段階では引数、名前、メンバが正確じゃないのは当たり前です。
新しい処理を追加する度に与えられたコンテキストが変化していないか目を光らせて、変化していた場合はすぐさま変更しましょう。
スコープを常に最少にする
スコープ、変数のライフタイムを常に自身の考えられる中での最少にすると自然と綺麗なコードになります。
スコープが最少になることを意識してコードを書くと自然に仕切りが必要になり、それが関数として分離できるようになります。
大部分で使わないメンバは現在のクラスに相応しくないのではないかと考える
多数のメンバと多数の関数を眺めてみると良く見つかるのですが、特定の関数グループでしか利用しない変数が存在することがあります。
クラスを分割するチャンスです。
クラスをまたがるコンテキストに注意を払う
2つのクラスの関係を見て、あまりに密に入出力を交換している場合は2つのクラスのためのラッパーを書いた方が良いかもしれません。
継承は使わない
特にC++の話ですが、継承は使わない方が良いです。
継承を使ってコードを綺麗に書けている人を今まで見たことがありません。
多くの場合、仮想関数やらポリモーフィズムやらオーバライドしているしていない、基盤クラスの肥大化によりスパゲッティ化します。
自分は良くても後から来た人は大体読みにくいと思ってます。
Mix Inなら有効な手法なので、こちらを意識できる人は使っても良いと思います。
そういう人はダックタイピングも分かるでしょうし、節度を守れそうです。
cppファイルでのクラス宣言はしない
これはC++の話です。
cppファイルで宣言されたクラスは他のファイルでは使えないので、有用なクラスを作ってしまうと悲惨です。
特にリファクタリングが嫌いで既存のコードへの修正を嫌う人が保守した場合地獄が待っています。
その有用なクラスしか取得できない情報を取得するためのコードが山のように追加されてあらゆるコンテキスがそのファイルに依存するようになります。
そうなると手練れでもそのファイルを依存の海から救い出すのは難しいでしょう。
全てに対して入出力を意識する
関数が入力を受け取って出力を生成するように、全てのプログラミング上の事象の入出力を常に意識すべきです。
生成したいものがあったとしたら、その生成に最低限必要なものだけを与えて生成したいものを生成することに集中すべきです。
このあたりが混ざったコードは簡単にスパゲッティ化します。意識しましょう。
また、具体的なインスタンス等が無かったとしても、何らかの副作用が発生する場合はそれも出力として意識すべきです。
ファイル、関数を巨大にしない
これは当たり前のことなんですが、何故か守れない人が多いです。
スコープ、依存を最少にすることを意識していたら、そのまま全部小さくできるはずです。
変数名やクラス名にはこだわる
適当な名前を付けるくらいなら当然説明的で変な省略語のない名前が良いです。
しかし、変数名は生ものです。コンテキストが変われば名前も変わってきます。
そういう時は素直にエイリアスを貼って別名を付けましょう。
また、スコープに合わせて変数名の長さを調節することも大事です。
長いスコープで存在するものには長い名前を、短いスコープで存在するものには短い名前を与えましょう。
許容されるのなら既存の汚いコードには従わない
無意味なプリフィックスやネームスペースを使っていなかったり、謎のフォルダ分けがあったりします。
そんな場合、コード管理者に問い合わせてそのルールに従わなくても良いか聞くと案外気にしていなかったりします。
まぁ、そんなコードになってしまっている時点で管理できていないのは当たり前なのですが。
なので、容赦なく無視して汚いコード文化を綺麗なコードで上書きしていきましょう。
大丈夫、綺麗なコードを書こうとしている貴方の方が絶対に良いコード文化を築けるはずです。
また、自身に権限があるのなら綺麗に書くことの助けとなるようなコーディング規約を策定すべきでしょう。
私のオススメは
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md
に従うことですが、膨大過ぎるので少しづつ増やしていくのが現実的かと思います。
毎月開催、自分頑張れよ会議
概要
8月の振り返りと9月の目標について
8月の振り返り
とりあえず、無事フリーランスになれた。
Rustの勉強はちょっとずつ進めている。
英語は相変わらず単語アプリで遊ぶ程度。
結局ブログも書こう書こうと思ってたけどこんな時期に。もう9月半分過ぎてるよ。
新しい環境と新しい仕事で忙しかったことにしておこう。
9月にできること
色々列挙してもTODOリストからすべきことに変化しないので、できると思うことだけに厳選
英語の単語アプリを完走する。
既にいくつかのアプリは完走しているので、そこまで苦労することなく完走できるんじゃないかと思う。
やっぱり大好きなC++関連じゃないとモチベーションが続かない気がするのでRustからのC++呼び出しをやってみようかと思う。
何度か調べた限りでは記事もそれなりにあるし多分そのまま実装できるのではないかと思う。
余裕があればUnityからのC++呼び出しについても何か書けたらと思う。
ここは前の仕事でやってた所なのでまとめる感じになるので時間さえ作れればいける。
ただ、直接の関数呼び出しに関しては上手くいかなかったのでそこを何とかしたい。
2017年8月の目標
概要
マイルストーンを置かないと人間はどこまでも怠惰になるので。
月初めに立てて、月終わりに見直そう。
したいこと
大き過ぎで小目標に向かないのもとりあえず書きだす。
C++
大好きC++。
私がC++のことをどうやって知っていったかという記事をいつか書きたい。
最近知った面白ネタとしては
がある。プライベート侵害である。合法とはいったい。
アクセスが許されないからってテンプレートから侵入してコンストラクタでポインタを無理矢理奪取してるの面白過ぎるでしょ
後はC++17についてもうちょい詳しくなりたい。
最近@pink_bangbiさんに
variant
を教わった。便利。
英語
最近話題になったシャーロックホームズが対訳で読めるサイト がカジュアルに英語に触れられるので重宝している。
ブログの更新
有意義な情報の発信を目指すと研究が進まない場合、長期間ブログが更新できない。
目標を立てることで進捗を確認するといういつでも気軽に書ける概念が手に入る。
少しも進まないくらいなら少しでも進んでいる感触を得た方がモチベーションを保てるかもしれない。
強制的なやるべき事があるとモチベーションが下がったりもするので用観察。
独自ドメイン運用上の問題
私はレンタルしているクラウドサーバをカジュアルLinux機として運用しているので
興味もったパッケージやアプリケーションを入れたりするので環境を初期化することを定期的にやってしまう。
こないだもGhostからWordPressに変更して独自ドメインのアドレスパスを無効にしてしまった。
この状態だと独自ドメインを安定運用することもできない。
安定したサーバを一つ用意しておき、そこから不安定なサーバに飛ばすようにするべきか。
今の格安サーバだとVMコンテナで管理するのは難しいのだろうか。
アクセスが集中するようなことは無いと思うので問題ない気はする。
Rust
最近勉強を始めた。まだまだ右も左も分からないよちよちプログラマー。
Rustのドキュメントは読み物としても面白い。エラーハンドリングだけでこの分量とか初心者を殺しにきている。
OSS
世の中のOSSはコードが汚いものが多く、リファクタリングをしたいと前々から思っている。
しかし、綺麗なコードは主観的な表現で絶対的な改善ではないため受け入れられないんじゃないかなと二の足を踏んでいる。
個人的には変数名を意味不明な省略表現から脱却するだけでもかなり読みやすくなると思うのだけれども。
今気になっているのはredisで有名な割にコード量が少ない。
Unity等にも持っていけるポータブルメモリインデータベースにならないかなとコードを眺めている。
モバイルまで見るのならrealmだろうが。
ゲーム制作
やってみてスケール感大き過ぎて諦めるが多過ぎるので、もっと適当に小さく作る必要がある。
完璧主義はゲームにおいては最悪な考え方だ。
クォータニオン解説
上記でもちょっと書いたが、複数環境でクォータニオンを運用するために詳しい知識を学習して共有したい。
文章書き
どんな駄文でも良いので20万文字かけたら、それには価値があると思っているのでそれを目指している。
1000字くらいなら簡単に書けても、それを200回繰り返すことができない。
とりあえず、頭を空っぽにして貪欲に文章を紡ぐ。内容や構成は最低限のステージに上がってからしようかと思う。
お絵かき
最低限アイコンくらい描けたら重宝しそうなので頑張っていきたい。
英語と同じで時間かけている割に上達しない。
VRお絵かき
凹さんとEsさんのアセットを使えば3D空間に落書きできるのは分かっているのでペンタブのトラッキングさえできれば簡単に実装できる。
TrackerもVive関連商品として存在しているが、ペンのような小さなものをトラッキングする方法はあるのだろうか。
最初は普通に3Dペインターをサクッと作っちゃった方が良いかもしれない。
上記2つのアセットが優秀なので多分1日もかからずに作れる。
就職
仕事しないと生きられないから仕方ないね。
前の仕事でVRをメインでやっていたので、VR関連が良い。
更に前の仕事でゲームを作っていたので、ゲームだとなお良い。
ただ、ソシャゲ以外のゲーム業界は給料安過ぎる上に古代の音が聞こえるので避けたいな。
オイラー角と空間座標系
概要
複数の環境間での回転のインポート、エクスポートについて調べていたのですが、全然進まないので最小限のアウトプットを目指したメモです。
オイラー角
説明はWikipediaに投げます。
重要なのは単にオイラー角といっても12通りの表現方法があることです。
今回の対象環境の1つであるUnityはz-x-y系を採用しています。
Z 座標を軸に z 度、X 座標を軸に x 度、Y 座標を軸に y 度 (順番はこのとおり) 回転する回転
オイラー角については上記座標系とCW(clockwise, 時計回り)とCCW(counterclockwise, 反時計回り)を合わせる事で他空間に同じ回転を適用することができます。
90度回転させると時計回りに回転するので、UnityではCWを使っているようです。
Tait–Bryan angles
航空力学で採用されている形式、 正面にX軸、右側にY軸、下方向にZ軸にそれぞれの正の値が割り当てられます。回転方向はCW。
オイラー角と違って軸の定義まで含まれています。
そして、ここまで厳密ではないと現実世界を定義できないのでジャイロセンサ等の出力はこの形式であることが多いです。
Quaternion
Quaternion Conventions: Hamilton and JPL
QuaternionにはHamiltonとJPL形式があるけど混同したり意識せずに混ぜて使ってしまっていることが多いよって話です。
Sensor Fusion
訳語が何になるかは分かりませんが、Sensor Fusionで検索すると参考になるものが色々出てきます。
Sensor Fusion · jherico/OculusRiftHacking Wiki · GitHub
参考
中途半端なbit幅の符号付整数を扱い易くするSign extending trick
charじゃ大きすぎる
charは何気に256もの数字を記録できます。
しかし、組み込みのような制限の厳しい環境では1bitでも送受信のデータは節約したいものです。
そんな時はbit演算を駆使してデータをやりとりすることになるのですが、困った状況というものがあります。
例えば、あるセンサーが-10~+10の値を返す場合どうやって値を管理すれば良いのでしょうか?
負の値を表現するには通常2の補数表現が使われますが、それを自分でやるしかないのでしょうか?
実はbit fieldを使えばそんな問題も簡単に解決できるようになります。
bit field
知らない人も多そうですが、データのやり取りの際にUnion等と一緒に使われることが多い機能です。
bit fieldでは指定した変数に割り当てるbit数が指定できます。
極々ローレベルな問題を扱うことが多いCならではの機能といえるでしょう。
書き方としては単純で、クラスや構造体のメンバ変数の最後にコロンと割り当てるbit数を書くだけです。
struct BitField { int a: 3; }; int main() { BitField bitField = {}; bitField.a = 0b0000; // 0 bitField.a = 0b0001; // 1 bitField.a = 0b0010; // 2 bitField.a = 0b0011; // 3 bitField.a = 0b0100; // -4 bitField.a = 0b0101; // -3 bitField.a = 0b0110; // -2 bitField.a = 0b0111; // -1 bitField.a = 0b1000; // 0 bitField.a = 0b1001; // 1 bitField.a = 0b1010; // 2 bitField.a = 0b1011; // 3 bitField.a = 0b1100; // -4 bitField.a = 0b1101; // -3 bitField.a = 0b1110; // -2 bitField.a = 0b1111; // -1
これでaには3bit以上の値が入らないようになります。
4bit目以降の数値は無視されていることが分かると思います。
そして、3bit目が補数表現のための負値の役割を果たしていることも分かります。
Sign extending trick
template <typename T, unsigned B> inline T signextend(const T x) { struct {T x:B;} s; return s.x = x; } int r = signextend<signed int,5>(x); // 5bitの符号付整数をintに変換する
まとめ
これで1byteに符号付整数を2つ入れてくるようなセンサーを相手にしても頭を抱えなくて済みますね。
template引数をbit fieldにも使う事ができるって面白かったので紹介してみました。
頭の片隅に置いておくといつか役に立つ日がくるかもしれません。
参考
http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend