先週Rustを触っていた。まだ手に馴染んでいないので少し不自由さを感じるが、慣れるまでの辛抱だろう。実際は去年くらいに一度インストールしてチュートリアル程度は済ませていたのだが、説明を見て言われた通りのコードを書く以上のことはしていなかった。なので、少し柔軟体操程度のことをしてみるか、とProject Eulerの問題をいくつか解いてみた。これは触ってみただけのひどく個人的な感想にすぎず、Rustの紹介を気合を入れてしている訳ではない。
続きを読むC++98でもvariantを(バリバリ)使いたい! その2
前回こういう記事が発生した。
c++98でもvariantを(バリバリ)使いたい! その1 - in neuro
このときは単に2つの関数をくっつけて即席visitor
を作れるようにして終わったものの、variant
は普通2つ以上詰め込むことが多いので、N個版をゴリゴリ展開していく必要に駆られている。
そもそもなんでこんなことになったのかというと、C++98にはvariadic templateがなく、またラムダもないからだ。
状況説明終わり。
続きを読むtomlのパーサを作った
こいついつもTOMLのパーサ書いてんな
C++で使えるheader-onlyなTOMLのパーサを書いた。実はこれは2度目である。何故またそんなことをしたか。順に説明していこう。
最初に書こうと思った一番の理由は、「パーサを書いたことがなかったのでいい経験になると思ったから」だ。他の理由の一つに「既存ライブラリのインターフェースがあまり好みでなかったから」というのがあるが、これは単なる好みの問題だと思うので深く突っ込まない(この好みには一応理由はあるが、労力をつぎ込むには根拠が薄弱すぎる)。
次に、今回書き直した理由は、「C++98のことを忘れてC++11以上のことだけ考えて書けばどうなるか」ということと、「以前の自分の設計とインターフェースに不満がでてきたから」だ。
今回の記事では、使い方の説明をREADMEよりは脱線しつつした後、最後に今回書き直した理由をダラダラと述べようと思う。
続きを読むerratum: 前回の記事に関して
前回の記事を書いた2日後くらいに、よく考えると先のコードはまずいのではという気もちになった。今日まで放置していたのは、まず自分が書いていたコードを直すことと、書かなければならない書類をこなすことに集中していたからだ。書類は数日前に草稿を共著者に送りつけた。穴だらけだとわかっているので、そろそろまた仕事が帰ってくるだろうが、今この瞬間は少し落ち着けている。もっと仕事を早くこなせるようにならねばならない。
さて、何がまずいかもしれないかというと、まずstd::vector
は(C++17以前は)要素型Tが完全形であることを要求している。よって、以下のような型はおかしいのではないか。
struct X
{
std::vector<X> xs;
};
ここで、struct X
の宣言が終わる最後の行まで、Xは完全形ではない。しかしその内部でstd::vector<X>
を使っている。ここではまだXは不完全型ではないのか。
ところでこれは動く。X x; x.xs.resize(10);
とかしても動く。そもそも気づかずに書いてしまった理由は、手元のいくつかのコンパイラで動いたからというのが大きい(C++erとしてはまだまだ未熟だ)。それに、書いているときはstd::vector
は内部的にはヒープにアロケートした配列へのポインタ、つまりここでX*
のようなものを持っているに違いないと思っていたため、動くだろうと考えたのだった。
だが実際には上記のように、std::vector
などコンテナの要素型は完全型でなければならない。ので上のコードが動いたのは、使ったSTL実装が動くようなものだったからで、つまるところ処理系依存な挙動をしたのだと思われる。ちなみに、C++17では不完全型のstd::vector
が作れるようになる。その代わり、アロケータ型が「アロケータ完全性要求」なるものを満たしている必要があるようだが。
よって、以上のような型を書いてはならず、C++17まで待つか、Boost.containerを使うとよい。これは不完全型をサポートしている。
上記リンクから飛ぶこともできるが、以下の記事で標準ライブラリと不完全型の話がなされている。http://www.drdobbs.com/the-standard-librarian-containers-of-inc/184403814
typedef typename trait::template something<T>::type type;
あるstructのメンバであるtemplate structをtemplate argumentとして受け取ってその中身をtypedefする、というときの書き方が(もう少し普通な状況でも出てくると思うが調べていない)、この18行目の文法がキモい2017だったので置いておく。
この書き方は寡聞にしてしらなかった
#include <iostream> #include <array> struct X { template<typename T> struct fixed_array; }; template<> struct X::fixed_array<double> { typedef std::array<double, 4> type; }; template<typename T, typename F> struct Y { typedef typename F::template fixed_array<T>::type type;//これ type container; }; int main() { typedef Y<double, X>::type type; type p{{1.,2.,3.,4.}}; for(auto&& item : p) std::cout << item << std::endl; return 0; }
しかし何度か書いてから見直すと自然に見えてくるのだから不思議だ。