日記

内容の正しさは保証しません

ノート 06/24

辞書式の並べ方にする方法
std::tupleを使う。正確にはstd::tupleの大小比較演算子を利用する。タプルの比較は最初の要素から比較し、等しい場合はまた次の要素から比較を始める。
例: make_tuple(1, 2, 3) < make_tuple(1, 2, 4)
最初の要素を比較すると1==1なので次の要素に移る。
2==2なのでまた次の要素を見る。
3<4なので式の値はtrueとなる。これは辞書の並び方の123→124を表している。

参照
operator==,!=,<,<=,>,>=(std::tuple) - cppreference.com

ノート 3/15

以前からやりたかったことは、json11に(key, var)の組のリストを与えて一括で変数varにアイテム名keyの値を代入することだった。これは前回のapply関数で実現できる。
次に、項目名keyの値を関数fで変換した後varに代入したくなった。

template <class T>
void bind(T const& t)
{
	if constexpr (util::is_tuple_v<T>) {
		util::apply(t, [this](auto& i) {
			i.var = i.functor(get<typename decltype(util::args(i.functor))::arg0>(json[i.key]));
		});
	}
}	

ここで、util::argsはファンクタの引数を得るためのヘルパ:

template <class ...Args>
struct parameter_pack {}; //型リストを比較する用

template <class F, class R, class ...Args>
struct args_impl {
	args_impl(R(F::*)(Args...) const);
	args_impl(R(F::*)(Args...));
	using arg0 = typename std::tuple_element<0, std::tuple<Args...>>::type;
	using pack = parameter_pack<Args...>;
};

template <class F>
struct args : decltype(args_impl(&F::operator())) {
	args(F);
};

参照:
C++ のラムダ式の引数型を推論する - Secret Garden(Instrumental)

また、組(key, var, functor)を与えるための構造体は:

template <class T> struct identity_function {
	T operator()(T t) const { return t; }
};

template <class S, class T, class F>
struct v {
	S const key;
	T& var;
	F functor;
	v(S const s, T& t, F&& f = identity_function<T>{}) : key(s), var(t), functor(f) {}
};

template <class S, class T, class F> v(S, T, F) -> v<S, T, F>;
template <class S, class T> v(S, T) -> v<S, T, identity_function<T>>;

テストコード

int main()
{
	std::string src = R"({"array1": [1, "one"], "array2": [[-1, -2], [-3, -4]], "id": 1})";
	省略
	j.bind(std::tuple{v{"array1", a}, v{"array2", b}, v{"id", c, [](int x){return (ID)(100);}}});
	std::cout << "------array1-------" << std::endl;
	std::cout << std::get<0>(a) << std::endl;
	std::cout << std::get<1>(a) << std::endl;

	std::cout << "------array2-------" << std::endl;
	for (auto const& ii : b) {
		for (auto const& i : ii) {
			std::cout << i << std::endl;
		}
	}
	std::cout << "------ID-------" << std::endl;
	std::cout << (int)c << std::endl;

結果

------array1-------
1
one
------array2-------
-1
-2
-3
-4
------ID-------
100

問題点1
ファンクタの引数のうち最初の1つしか得られない。
本当は

template <class std::size_t N> using arg = ...;

と書きたいが、うまくいかない…

問題点2
args周りが汚すぎる

今回分かったこと・疑問点
クラステンプレートの内部にエイリアステンプレートを書けない?
 その解決策の1つに継承がある
C++分からん…入門すらできてないのがよく分かった(+_+)

次にやりたいこと
関数fから逆関数を生成(std::mapを使った限定的なもの)
bindに与えたリストを保存する
dump(bindの逆)を行う

#全体的に汚いのはなんとかしたい
#書いているときは気がつかなかったけど、使いどころがあまりない

ノート 2/17

最近再びC++を書くようになった。元々そんなに書いていないが、リハビリ中。

#include <tuple>
#include <functional>

template <class Tuple, class F>
void g(Tuple&& tuple, F&& f)
{
	std::apply([](auto&& ...args) { (f(args), ...); }, tuple);
}

tupleに対してf(x_0), f(x_1), ..., f(x_n-1)がやりたかった。
仕組みをメモ
(1) applyによりtupleを分解する
(2) fold式 (f(args), ...)により(f(args#0), (f(args#1), (f(args#2), (...) )))を書いたことになる

参照
cpp17book/019-cpp17-core-fold-expressions.md at master · EzoeRyou/cpp17book · GitHub

自作パソコンの備忘録

この記事は随分前に書いたが投稿を忘れていました。

前提
・工作とかは全く経験無しだった
・CPUやメモリの役割は知っている

注意事項
検索エンジンを使うときは1年以内の情報のみ表示する。予想よりずっと流れが早い。

1 パーツ選び
必要なパーツは次の9種。
CPU, グラフィックボード, マザーボード, 電源ユニット, メモリ, CPUファン, ストレージ(SSD, HDD), ケース, OS

CPUとグラフィックボードから選ぶ。良くわからなければ適当にコスパ重視の組み合わせを調べる。
次にケースを選ぶ。大きさによって置き場所はもちろんだが搭載できるCPUファンとケースファンとマザーボードも異なる。
次はマザーボードを選ぶ。制約があり、全て満たさなければならない。
 (a)CPUのソケットと一致したソケットを持つこと
 (b)CPUに対応したチップセットを搭載すること
 (c)グラフィックボードを搭載するのに必要な本数、PCIe x16スロットがあること
 (d)ケースに搭載可能な大きさであること
大きさについては、ATX, Micro ATX, Mini ITXなどの規格がある。

ここからは並行して選ぶことができる。
・電源ユニット
条件はケースに搭載できる大きさのものであることと、CPUとグラフィックボードとマザーボードの最大消費電力より数十%以上大きい容量であることの2つ。

・メモリ
条件は2つ。1, CPUに対応した規格であること 2, マザーボードのメーカー側で動作確認済みであること
規格にはDDR4 SDRAMがある。
本当はランクも考慮する必要があり、シングルランクとデュアルランクの二種類のうちどちらかがCPUにとって最適かもしれない。見分けられなかったので動作確認済みならとりあえず良しとした。

・CPUファン
CPUに付属していることがあり、実際そうだったので詳しくは知らない。

・OS
CPUとOSの双方がサポートしているものに限る。初めにサポート外のOSをインストールするのに挑戦したが、グラフィックドライバが入れられなくてハードウェアアクセラレーションが有効にできずOSを変える事態になった。

・ストレージ
2つ以上。1つはOS用にする。

2 組み立て
まずはマザーボードに基本的なパーツ(メモリ, CPU, CPUファン, グラフィックボード, 電源ユニット)を取り付ける。

・メモリ
音がするまで奥に差し込む。モヤシ人間的にはかなり力を入れないと入らなかった。怖いので動画見たほうがいいと思う。

・CPU
ピンが壊れないように慎重に取り付ける。穴に合っていればCPUが浮くことはない。

・CPUファン
ピンを差し込むタイプとネジで止めるタイプの2つがあるらしい。ネジで止める場合は締めすぎに注意する。以降、ネジが4つ以上なら対角線上に締める。ファンだけでマザーボードを持ち上げられるなら十分だと思う。

・グラフィックボード
今回はオンボードだったので知らない。

・電源ユニット
説明書とコードの形状と印字をよく見て間違えないように挿す。

ここまで来たらモニタも繋いでBIOSを起動してみる。この際電源を入れるにはマザーボードの電源スイッチをオンにするかピンをショートさせる。
ショートさせるにはプラスとマイナスの端子が必要だが説明書に書いてなくて苦労した。結局GNDとしか書いてない謎の端子(いきなり出てくるとそう見える)がマイナスに相当することが分かった。
BIOSが起動できたらケースに組み込む。BIOSは電源ユニットのスイッチを切って終了すれば良い。

ここで、組み込む前にマザーボードに付属しているIOシールド(バックパネル)をマザーボードに取り付けられるか、バックパネルのツメを曲げて調整し確認する。

以降は説明書どおりかつ端子を奥まで差し込んでいるか確認しつつ作業を進めれば完成。

3 その他の学んだこと
・ネットの評判は不具合の方は多少アテにできる
初期不良を疑う場合はワンコイン診断に出す(または、持っていく)
・同じお店で購入すると相性保証などがあって安心だが、相性がある部品は多分メモリのことで、メモリは動作確認済みのを購入すれば店舗を揃えなくても問題ない…たぶん
・OSをインストールする際はストレージを1つだけ接続して行う。さもないと2つ以上のストレージにOSがバラバラに置かれ、修正には小難しいコマンドを入力するか再インストールが必要になる。

7/1のノート c++17

江添亮の詳説C++17
気になった項目を列挙する

constexpr if
テンプレートで使う
std::is_sameと併用して型によって処理を分岐させるようにできる

if (condition) {
... //もしここを通らなくても...が実行(実体化)できないといけない
}

if constexpr (condition) { //ここだけ必ず実体化される
... //trueのときだけ実行できればOK
}

構造化束縛
配列, std::pair, std::tuple, 構造体(staticを除きprivateデータメンバ無し)に対して使えて

auto [a, b] = make_pair("abc", 123);

for文でも使えるのが面白い

std::map<std::string, int> table = {
	{"abc", 123},
	{"def", 456}
};

for (const auto& [key, value] : table) {
	std::cout << key << "=>" << value << std::endl;
}

variant
たくさん書いてあるので重要な感じがするが気が向いたら読む

any
なんでも入る。何に使うんだろう

apply
tupleの要素を実引数として関数を呼び出す

template <class ...Args>
void f(Args... args);

std::tuple t(1, 2, 3);
apply(f, t); //f(1, 2, 3);

おもに可変引数テンプレートのパラメータパックを扱うために存在する?

make_from_tuple
tupleの要素を実引数としてコンストラクタを呼び出し、オブジェクトを返す

insert_or_assign
std::mapまたはunordered_mapで値を設定するとき、新規にkeyとvalueの組を作るとき(inserted)はtrue, それ以外はfalseをイテレータとともに返す

std::map<std::string, int> m = {{"abc", 123}};
auto [it, inserted] = m.insert_or_assign("abc", 456);
//inserted == false

ノート 18/5/3-6/3

DLL関連が2つ、あとwxWidgets、それと1つ未解決の問題

1. エントリポイントが見つかりません
前回作成したhelloを何気なく-o hello.exeとしてビルド、ダブルクリックで実行しようとしたら「エントリポイントが見つかりません」。
原因は同名DLLが衝突しているせい。

対処法
(1)ldd ./hello.exeで共有ライブラリを確認し、system32以外(mingw/binなど)の場所にあるものを見つける
(2)システム環境変数の編集からシステム環境変数のpathを見る
(3)pathの中身を1つ1つ確認し、衝突しているDLLを見つける
(4)pathを編集して先に読み込みたい方のDLLがあるパスを衝突している方より上に書く
もしくはパスから削除

参照
MinGWでHelloWorld(Gtkmm3版)に成功した - やってみる

あるいは、DLLを実行ファイルと同じディレクトリに置いて実行できるのを確認し、衝突していると思うDLLを除いて再びエントリポイントが見つかりませんと怒られることでも問題のライブラリを発見できる。

2.静的リンク
libstdc++を静的リンクしようとするとlinker command faild with exit code 1.またlibgccの場合は無視されているようで、lddで確認すると普通にlibgcc xxxx.dllが見える。素直に諦めるが吉

3. XRC
wxWidgetsで部品とコードを分離するために使う。wxFormBuilderがインストールも使い方も簡単でいい感じだった。wxGladeも使おうとしたけどwxPythonをインストールするまでの道のりが長くて諦めた。

参考
Tips of wxWidgets. - Luoyang Press

4. テンプレート関数の引数にconst参照があるとlinker command faild with exit code 1.
picojsonはコードが冗長だからjson11を使っていたのだが、こちらもパースの処理が長くなって良くない。結局簡単にするための関数を書くことにした。

template <class T> T& get(T&, const json11::Json&);

template <> bool& get<bool>(bool& b, const json11::Json& j) { return b = j.bool_value(); }
 `json11::Json::bool_value() const' ▒ɑ΂▒▒▒▒`▒▒▒▒Ă▒▒Ȃ▒▒Q▒Ƃł▒
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

何言ってるか分からないけど、とにかくエラー。g++使うと

undefined reference to `json11::Json::bool_value() const'
collect2.exe: error: ld returned 1 exit status

多分json11::Json::bool_value()が未定義という意味だった。(そのまま)
原因は見当もつかない。とりあえずコードを参考というかパクった元のを真似てstatic inlineをつけたらclang++では直った。g++では直らない。
頭からすっかり抜けていたんだけど、json11はヘッダだけではなかった。近年稀に見る間抜け。

template <class T>
static inline T& get(T&, const json11::Json&);

template <>
inline bool& get<bool>(bool& b, const json11::Json& j) { return b = j.bool_value(); }

wxWidgetsを使う

環境
Windows10, msys2, clang, wxWidgets3.0.4

1. ビルド

上手くビルドできたようなのでコマンドを書いておく

./configure CC="clang" CXX="clang++ -std=c++17 -DwxNO__T -DHAVE_TYPE_TRAITS -Wno-narrowing" \
--disable-shared --enable-monolithic --enable-stl --with-cxx=17 -disable-threads
  • Wno-narrowingをつけると、一つ前の記事のエラーが消える。(clang君が-Wc++11-narrowingとか言うからてっきりそっちかと…)

注意
必ず環境変数MSYSTEMにMINGW64かMINGW32をセットしておく

参照
nyaocatの日記 2016-04-21
wxWidgets をビルドする | 雑記帳
wxWidgets 2.9.3 を C++11 としてコンパイルする (Mac OS X 10.7 Lion) - Qiita

2.テスト

#include <wx/wxprec.h>
#include <wx/wx.h>

class Hello : public wxApp
{
public:
	virtual bool OnInit();
};

IMPLEMENT_APP(Hello)

bool Hello::OnInit()
{
	wxMessageBox(wxT("こんにちわ"), wxT("メッセージ"), wxOK);
	return false;
}
clang++ -c -o hello.o hello.cpp $(wx-config --cxxflags) -std=c++17
clang++ -o hello hello.o $(wx-config --libs) -std=c++17
./hello

実行結果
f:id:CitrusJ9N:20180512185618p:plain

参照
wxWidgets
My Future Sight for Past: Install wxWidgets 2.8.12 from source on Cygwin with MinGW-w64