Visual Studio 2017でNanaを試す
長らく記事を書いていなかった。サボりすぎだ。
やはり良いコードを書く人というのは、記事を多く投稿し技術を発信している。自分も頑張ろう。
Nanaとは?
C++でGUIを書こうと思ったとき、幾つかの選択肢が存在する。
例えば、Qt、wxWidgetなどの名前が挙がるが、今日紹介するのは日本ではあまり記事を見かけない、Nanaというライブラリだ。
Nana C++ Library - a modern C++ GUI library
Nanaは、WindowsとLinuxで動くクロスコンパイル可能なGUIライブラリだ。
最大の特徴は、
と、モダンなC++コードでGUIを書くことを意識されたライブラリであることだ。
非常に興味深いので、環境構築から簡単なコードのコンパイルまでを記事に残しておこうと思う。
環境は、Windows 7 SP1 32bit、そしてVisual Studio Community 2017だ。
なお、Macは"experimental"であるとの事だ。
リポジトリのcloneとビルド
Nanaは現代の流れに乗り、例外なくオープンソースだ。
GitHub - cnjinhao/nana: a modern C++ GUI library
githubから最新のソースをcloneしてくる。
$ git clone https://github.com/cnjinhao/nana.git nana
次に、includeフォルダを環境変数に登録する。変数名は好きなので良い。
例えば筆者はNANA_INCLUDEなどとした。nanaフォルダ直下のincludeを登録する。
そしてbuildフォルダに存在するvc2015のnana.slnをVS2017で開く。
その際、何も意識せずVS2017へアップコンバートすれば良い。
プロジェクトのプロパティからインクルードパスを追加する。
追加のインクルードパス
>$(NANA_INCLUDE)
筆者の環境ではVS2017ではWindows 10のSDKしか入れてなかったので、
必要に応じて、構成プロパティ>全般 から「Windows SDKバージョン」を8から10に変えておく。
次にそのままではビルド後問題が発生するので、include\nana\c++defines.hppを以下のように改変する
#if (_MSC_VER >= 1900) // <= _MSC_VER == 1900をこのように // google: break any code that tries to use codecvt<char16_t> or codecvt<char32_t>. // google: It appears the C++ libs haven't been compiled with native char16_t/char32_t support. // google: Those definitions are for codecvt<wchar_t>::id, codecvt<unsigned short>::id and codecvt<char>::id respectively. // However, the codecvt<char16_t>::id and codecvt<char32_t>::id definitions aren't there, and indeed, if you look at locale0.cpp in the CRT source code you'll see they're not defined at all. // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. #define STD_CODECVT_NOT_SUPPORTED #endif // _MSC_VER == 1900
後はそのままDebugモード、Releaseモードでそれぞれビルドする。
問題なければ、nana\build\bin直下に2つのlibが生成されるはずだ。
これでライブラリのビルドは完了した。
このままでも使えるが、例によって環境変数を登録すると楽なので筆者は環境変数を登録した。
環境変数を使わない場合は以降で説明する追加のライブラリディレクトリに、binのパスを指定する。
プロジェクトの作成
Visual Studioをたちあげる。
プロジェクトの新規作成から、「Visual C++ > Win32 コンソールアプリケーション」を選択する。
プロジェクトの作成ウィザードで、必ず「空のプロジェクト」にチェックを入れておくこと。
ソースファイルに適当にファイルを追加したら、プロジェクトの設定を行う。
結構めんどくさいので、マクロか何かで定義しても良いかもしれない。
- [全ての構成]で行う
C/C++ > 全般
追加のインクルードパス:$(NANA_INCLUDE)
リンカー > 全般
追加のライブラリディレクトリ:$(NANA_LIB)
- C/C++ > コード生成
[Debug]
ランタイムライブラリ > マルチスレッドデバッグ(/MTd)
[Release]
ランタイムライブラリ > マルチスレッド (/MT)
- リンカー > 入力
[Debug]
追加の依存ファイル > nana_v141_Debug_x86.lib
[Release]
追加の依存ファイル > nana_v141_Release_x86.lib
後は公式に載っているサンプルをビルドしてみよう。
#include <nana/gui.hpp> #include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/button.hpp> int main() { using namespace nana; //Define a form. form fm; //Define a label and display a text. label lab{ fm, "Hello, <bold blue size=16>Nana C++ Library</>" }; lab.format(true); //Define a button and answer the click event. button btn{ fm, "Quit" }; btn.events().click([&fm] { fm.close(); }); //Layout management fm.div("vert <><<><weight=80% text><>><><weight=24<><button><>><>"); fm["text"] << lab; fm["button"] << btn; fm.collocate(); //Show the form fm.show(); //Start to event loop process, it blocks until the form is closed. exec(); }
以下のウィンドウが出てくるはずだ。
環境構築の記事を書いただけで良い時間になり疲れてしまった
実はまだ深く触れていない。なのでまだこのライブラリのモダンな部分には少ししか触れていない。
これから触ってリポートして行きたいと思う。
どうやらマウスクリックなどのイベントにラムダを流し込む事なども出来るようだ。
また、列挙子が必要な時は、基本的にscoped enumを使っているのも興味深い。
どこまでこのライブラリがモダンに染められているのか、業務の合間に機を見て触ってみようと思う。
メンバ変数のHidingの練習
いいわけ
今週末は少々忙しかったので記事を書く余裕がなかった。
......というのは言い訳であまり今週は記事に出来るようなテクニックに触れてこなかった。
貝柱ではなく別のアカウントで、「同じ課題」に対して多数の言語でプログラムを書くという練習を行った。
そちらを記事にしても良いのだが、別件でもう少しプログラム内容について精査したいので、また改めて後日ということにする。
Scalaにもう少し深く触れたい。
まえがき
C++ではクラスを継承する際、継承元のメンバ変数を完全に上書きして"隠す"技が存在する。
俗に「Hiding」などと呼ばれるが、あまり良い実用例が思い浮かばない。
コード
何かに使えそうなテクニックだ。
どこかで使われているなら、ぜひ教えてほしい。
#include <iostream> #include <functional> //Base構造体 struct Base{ std::function<void(int)> showInt; }; //Baseから派生した構造体 struct SameBase : public Base{ std::function<void(int, int)> showInt; }; int main(void){ SameBase base; base.showInt = [=](int value,int value2){ std::cout << "show:" << value + value2 << std::endl; }; base.showInt(20, 30); return 0; }
上記のコードは継承元のshowIntをHidingしている。
overrideやoverloadとはまた違い、また別のテクニックとして何かできないだろうか?
Template Parameter PackをReverseする
まえがき
C++ではもはやおなじみになったTemplate Parameter Pack。今回はこれについてだ。
例えば、以下のように引数に与えられた値を出力するだけの関数があるとする。
template<typename Ty> void shower(Ty head) { std::cout << head << std::endl; } template<typename Ty, typename... Ts> void shower(Ty head, Ts... tail) { std::cout << head; shower(tail...); }
これに対して、与えた逆順に出力してほしいものとする。
パラメータパックの逆展開だ。
コード
これには、stackoverflowの記事が大変参考になった。
c++ - How to reverse the order of arguments of a variadic template function? - Stack Overflow
これを基に以下のようにコードをおこした。
#include <iostream> template<typename Ty> void shower(Ty head) { std::cout << head << std::endl; } template<typename Ty, typename... Ts> void shower(Ty head, Ts... tail) { std::cout << head; shower(tail...); } template<typename... Tn> struct revert; template<> struct revert<> { template<typename... Un> static void apply(Un const&... un) { shower(un...); } }; template<typename Ty, typename... Ts> struct revert<Ty, Ts...> { template<typename ...Un> static void apply(Ty const& t, Ts const&... tail, Un const&... un) { revert<Ts...>::apply(tail..., t, un...); } }; template<typename Ty, typename... Ts> void reverse_shower(Ty const& val, Ts const&... tail) { revert<Ts...>::apply(tail..., val); } int main(void) { reverse_shower(1, 2, 3, 4, 5); /* reverse_shower<int, int ,int ,int ,int>( 1, 2, 3, 4, 5 ) revert<int, int, int, int>::apply(2, 3, 4, 5, 1) revert<int, int, int>::apply(3, 4, 5, 2, 1) revert<int ,int>::apply(4, 5, 3, 2, 1) revert<int>::apply(5, 4, 3, 2, 1) revert<>::apply(5, 4, 3, 2, 1) shower(5, 4, 3, 2, 1) */ return 0; }
非常に美しいテクニックだと思う。
実際に実用に取り入れられるかは分からないが、何かで実践的なコードを書いてみたい。
継承先のクラスポインタを格納した親ポインタに適切なクラスを構築する
まえがき
今、SuperというクラスからAとBが派生しているとする。
C++では、Superのポインタには、継承関係にあるAのインスタンス、Bのインスタンスがそれぞれ格納できる。
例えば以下の様な感じだ
Super* ptr = new A(); Super* ptr2= new B();
では、格納しているインスタンスによって、新たに親クラスポインタに派生したクラスポインタを格納したい場合はどうすればよいのだろう?
Super* ptr = new A(); //ただし、場合によってはnew B()となりうる Super* ptr2 = ???; //ptrの内容にあわせてAかBのインスタンスを格納したい
今回はこれを実現する
アプローチ
クラスが親子関係にあり、親クラスのメソッドを子クラスが継承したとする。
例えば、Superにshow()なるメソッドがあり、子クラスがそれを継承しているとすると、
次のコードでは
Super* ptr = new A();
ptr->show();
Superのshow()ではなく、Aのshow()が呼ばれる。これは多態性と呼ばれる特性によるものだ。
これを使い、自分自身のインスタンスを作成し返すファクトリ関数のようなものを持つことで、主題の問題を解決する
コード
#include <iostream> #include <memory> struct Super { virtual void show() { std::cout << "I am Super" << std::endl; } virtual std::unique_ptr<Super> make_me() = 0; }; struct A : public Super { void show() override { std::cout << "I am A" << std::endl; } std::unique_ptr<Super> make_me() override { return std::unique_ptr<Super>(new A()); } }; struct B : public Super { void show() override { std::cout << "I am B" << std::endl; } std::unique_ptr<Super> make_me() override { return std::unique_ptr<Super>(new B()); } }; int main(void) { std::unique_ptr<Super> ptr_A = std::make_unique<A>(); std::unique_ptr<Super> ptr_B = std::make_unique<B>(); std::unique_ptr<Super> ptr_g = ptr_A->make_me(); ptr_g->show(); // I am A ptr_g.reset(); ptr_g = ptr_B->make_me(); ptr_g->show(); // I am B return 0; }
1つだけ値が有効な変数群を作成する
まえがき
前回の記事からこの記事を書くまでにメインマシンに入れいているVisual Studioがバグってしまった。
具体的には起動時、VC++のテンプレートが見当たらなくなってしまった。それに基づき、C++のプロジェクトソリューションも正常に開くことが出来なくなってしまった。
Visual Studioフォーラムにも質問したが、望む回答が得られなかった。
この問題はVisual Studioを一旦完全にアンインストールし、再度Visual Studioをインストールすることで解決した。
下記記事が参考になった。
Visual Studio Uninstaller でvisual studio 2015 を完全アンインストール - Qiita
貝柱の環境では何回かexeを起動しなおさなければ完全にアンインストール出来なかった。
さて、前回に引き続き、今回の記事も万人向けとは言いがたい。
内容が中々にただC++で遊んでいるだけのものだが、暇な人はお付き合い願いたい。
動機
Windowsのコントロールの中にラジオボタンというものがある。
例えば、A B Cなどというラジオボタングループがあったら、そのウチ一つしか選べないようなコントロールだ。
これを管理しようと思うとどうなるだろうか?
例えば、以下のように単純に配列で管理する。
bool radio[3] = {true, false, false};
この場合、配列へのアクセスを管理する関数を別で用意して、配列の中のどれか一つだけをtrueにする。
しかし、C++を使っているならばクラスとして管理したい。
クラスとして管理すれば、アクセサを介するのでどれか一つがtrueになる事は保証できるだろう。
配列ならば管理も容易だ。
ラジオボタンの意味を持たせながら変数名を付けたいときはどうだろうか?
//ラジオボタン群... bool chocolate = true; bool coockie = false; bool syrup = false;
変数名に意味合いがあると可読性がぐんとあがる。
だが代わりに管理が面倒だ。欲をいえば、例えば上記の例ならば、
coockie = true; //これをした時点で assert( chocolate == false ); assert( syrup == false ); // これが満たされて欲しい
これを実現する。
アプローチ
以下にコードを示す。
#include <iostream> #include <vector> #include <functional> #include <memory> //型を梱包するもの template<typename Ty> class FlaggedType { public: //ctor FlaggedType() { setter = &FlaggedType<Ty>::set; } virtual ~FlaggedType() = default; //=operator FlaggedType<Ty>& operator=(const FlaggedType<Ty>& other) { *this = other.val_; return *this; } FlaggedType(const FlaggedType<Ty>& other) { *this = other; } FlaggedType(const FlaggedType<Ty>&& other) { val_ = std::move(other.val_); ptr_ = std::move(other.ptr_); initializable_ = std::move(other.initializable_); } operator Ty() { return val_; } Ty& operator=(const Ty& val){ //setterを経由した代入 if (setter) { setter(*this, *this, val); } return val_; } //setter void set(FlaggedType<Ty>& base, const Ty& val) { base.val_ = val; } void only_set(FlaggedType<Ty>& base, const Ty& val) { //set処理によって値が変更される恐れがある //ダサいが一旦値をコピーしておく Ty value = val; //他の変数の値を初期化しつつセット for (auto& ele : base.ptr_) { ele->val_ = ele->initializable_; } base.val_ = value; } //setterを格納するstd::function std::function<void(FlaggedType<Ty>, FlaggedType<Ty>&, const Ty&)> setter; //private: //実際に自分が格納している値 Ty val_; //自身以外の他の変数ポインタを持つもの std::vector<std::shared_ptr<FlaggedType<Ty>>> ptr_; //自身が取るべき初期値 Ty initializable_; }; template<typename Ty> void makeUniqueFlag(const Ty& initializable, std::vector<std::shared_ptr<FlaggedType<Ty>>>& vec, FlaggedType<Ty>& one) { //初期化値をセットし、リソースを破壊しないようにしながらポインタ作成 one.setter = &FlaggedType<Ty>::only_set; std::shared_ptr<FlaggedType<Ty>> ptr(&one, [](FlaggedType<Ty>*) {}); //格納 vec.push_back(std::move(ptr)); //格納 for (auto& ele : vec) { ele->initializable_ = initializable; ele->ptr_ = vec; } } template<typename Ty,typename... Ts> void makeUniqueFlag(const Ty& initializable, std::vector<std::shared_ptr<FlaggedType<Ty>>>& vec, FlaggedType<Ty>& head, Ts&... flags) { head.setter = &FlaggedType<Ty>::only_set; std::shared_ptr<FlaggedType<Ty>> ptr(&head, [](FlaggedType<Ty>*) {}); //格納 vec.push_back(std::move(ptr)); makeUniqueFlag(initializable, vec, flags...); } template<typename Ty,typename... Ts> void makeUniqueFlag(const Ty& initializable, Ts&... flags) { //ptrの初期化 std::vector<std::shared_ptr<FlaggedType<Ty>>> ptr_vec; makeUniqueFlag(initializable, ptr_vec, flags...); } //Unionの解除 template<typename Ty> void resetUniqueFlag(FlaggedType<Ty>& value) { value.setter = &FlaggedType<Ty>::set; value.ptr_.clear(); value.ptr_.shrink_to_fit(); } template<typename Ty, typename... Ts> void resetUniqueFlag(FlaggedType<Ty>& head, Ts&... flags) { head.setter = &FlaggedType<Ty>::set; head.ptr_.clear(); head.ptr_.shrink_to_fit(); resetUniqueFlag(flags...); } int main(void){ FlaggedType<bool> red; FlaggedType<bool> blue; FlaggedType<bool> yellow; red = true; blue = false; yellow = false; auto show_bool = [](const bool& boolean) { return (boolean ? "true" : "false"); }; std::cout << "red:" << show_bool(red) << std::endl; std::cout << "blue:" << show_bool(blue) << std::endl; std::cout << "yellow" << show_bool(yellow) << std::endl; std::cout << "make unique flag" << std::endl; makeUniqueFlag(false, red, blue, yellow); blue = true; std::cout << "red:" << show_bool(red) << std::endl; std::cout << "blue:" << show_bool(blue) << std::endl; std::cout << "yellow" << show_bool(yellow) << std::endl; return 0; }
おそらくこのアプローチは完全ではない。
まず持つべきデータメンバをWrapしておきながらその実、publicになっており外部から容易にアクセスできる。
次におそらくsetterなどの渡し方はもう少し賢い方法があるはずだ。
実は記事の投稿が遅れたのは、このテーマを投稿しようとして解説文を考えていたが
色々と穴があり、結局良いアプローチが思い浮かばなかったというのもある(言い訳)。
たっぷりと時間が許された時に、もう少し綺麗に書いてみたいものだ。
非型テンプレートパラメータに指定できる値の制限をする
自分の中でHotなうちに記事に書きおろそうと思う。
タイトルは非型テンプレートパラメータに制限を、と書いているが、doubleが使えないとかそういう事ではない。
もう少し単純な話だ。なお、この話はコアなのであまり万人には役に立たないかもしれない。
あと、以下の記事はVS2013で主に発案したので本来はconstexprを使用しなければならない所が多数ある事、
また、逆にいうとconstexprが使用できない制限下で行ったことを把握願いたい。
動機
C++ではご存知の通りテンプレートという強力な機構が存在する。
通常テンプレートパラメータには型を指定するが、次のように値を指定する事ができる。
template<int V> struct Hoge{ static const int value = V; }; int main(void){ std::cout << Hoge<10>::value << std::endl; }
上記を非型テンプレートパラメータなどという。
ところで、ここで渡すパラメータに制限を持たせることはできないだろうか。
例えば正の整数のみで、負は許可しない。 以下のようなコードを書いた時、Hoge<-1>によってコンパイルエラーになってほしい。
Hoge<10>::value; // ok. これは許可する Hoge<-1>::value; // no. これは許可しない
これを実現する。
アプローチ
まず必要になるのは、こちらが望む制限を実装するメタ関数だ。
これは単純に以下のように実装できる。
//内部に定数式が正負だったかの真偽値を持つメタ関数 template<int val> struct is_positive{ static const bool value = (val >= 0); }; int main(void){ if( is_positive<10>::value ){ std::cout << "true" << std::endl; } return 0; }
メタ関数is_positiveは内部valueに、非型テンプレートパラメータが制限を満たすかのbool値を持つ。
次に目的のクラスの実装を、以下のように行う
template<bool B, int V = 0> struct positive_struct{ positive_struct() = delete; }; template<int V> struct positive_struct<true, V>{ positive_struct() = default; static const int val = V; };
上記の実装はstd::enable_ifを参考にした。
こうすることによって、positive_structは第一テンプレートパラメータの真偽値によって、内部にvalを持つ場合、あるいはインスタンス化を抑制できる。
これを先ほどのメタ関数と合わせる。
#include <iostream> //内部に定数式が正負だったかの真偽値を持つメタ関数 template<int val> struct is_positive{ static const bool value = (val >= 0); }; template<bool B, int V = 0> struct positive_struct{ positive_struct() = delete; }; template<int V> struct positive_struct<true, V>{ positive_struct() = default; static const int val = V; }; template<int V> using positive_struct_decl = positive_struct< is_positive<V>::value, V>; int main(void){ std::cout << positive_struct_decl<20>::val; // std::cout << positive_struct_decl<-15>::val; これは存在しないのでコンパイルエラーになる // positive_struct_decl<-1> hoge; これもエラー return 0; }
実際には宣言を容易にするためにエイリアステンプレートを使う。
この実装を使えば、非型テンプレートの値によるインスタンス化の制限もできる。
また、嬉しい副作用としてVS2013以降ならば、コードを記述しただけでインテリセンスが働き、波線で注意してくれる。
(他のC++ IDEもいけるのかもしれない)
あとがき
なかなか需要がない実装かもしれない。
実際これを使おうと思った時にはどういう目的で使おうとしたのか忘れてしまった。
だが、せっかくなので記事にしてみた。 あと、やはり記事を書くのは時間がかかってしまう。
この記事を書きながら「この美術部には問題がある!」を見ていたのだが、自分も頭の中に思い描く嫁をあのようにキャンバスに上手く表したいものだ。
メモリリーク検出器とstd::unique_ptr
久し振りに書く記事はC++は書けたがC++11をやりたての貝柱が実際にハマったことについて書こうと思う。
もちろん今でもその疎さはまだまだ解消されていないので初心者といえる。
はてなブログも久し振りに書くのでそのリハビリにも良いかもしれない。使い勝手が色々変わっていてまだ良くわかっていない。
貝柱は仕事柄C++のIDEとしてVisual Studioを使っている。
もちろん都合上生ポインタも扱うのでメモリリークには気を使う。
Visual Studioには便利なメモリリーク検出器があり、Win32プロジェクトのDEBUGモードなら以下のコードによってメモリリークを検出できる。
#include <iostream> //======== メモリリークの検出器 =======// #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include <crtdbg.h> #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #endif int main(void){ //..... do something .....// _CrtDumpMemoryLeaks(); return 0; }
例えば、生ポインタを扱っていて、開放し忘れを検知したい時にこのコードは威力を発揮する。
_CrtDumpMemoryLeaks();
までにnewしたのにdeleteしなかったメモリが存在する場合、コンパイラは例えば以下のようにメモリダンプを吐き出す。
{63} normal block at 0x003F6A00, 80 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
ところで、C++11で追加されたstd::unique_ptrは、宣言したスコープから外れると、自動的に確保したメモリをdeleteしてくれる便利なスマートポインタだ。
例えば以下のような使い方をする。
{ std::unique_ptr<int> p(new int(100)); } //ここでpは開放される
そこできちんとstd::unique_ptrによってメモリが開放されてるかを確認したいとする。
ハマったのは以下のように使用した時だった。
#include <iostream> #include <memory> //======== メモリリークの検出器 =======// #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include <crtdbg.h> #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #endif int main(void){ std::unique_ptr<int> p(new int(2)); _CrtDumpMemoryLeaks(); return 0; }
この例ではメモリリークを検知してしまう。何故だろう。答えは本当に至極単純だ。
_CrtDumpMemoryLeaks()はその時点で開放されていないメモリをダンプする。
一方std::unique_ptrの開放タイミングはそのスコープが外れる時だ。すなわち、_CrtDumpMemoryLeaks()の後になる。
_CrtDumpMemoryLeaks()はスコープから外れていないstd::unique_ptrのメモリをメモリリークとみなし、ダンプしてしまうわけだ。
なので、以下のようにコードをスコープで囲まなければならない。
#include <iostream> #include <memory> //======== メモリリークの検出器 =======// #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include <crtdbg.h> #define new new(_NORMAL_BLOCK, __FILE__, __LINE__) #endif int main(void) { { std::unique_ptr<int> p(new int(2)); } _CrtDumpMemoryLeaks(); return 0; }
初歩的なミスで熟練には笑われてしまうかもしれない。
特にカスタムデリータのテストをしたい時などに短いプログラムを書くときは、注意しておこう。