boost::regex は Perl みたいな感じで正規表現を使わせてくれるライブラリ。
#include <iostream> #include <boost/regex.hpp> int main() { using namespace std; using boost::regex; using boost::sregex_token_iterator; string s("a/b c/d e/f"); sregex_token_iterator i(s.begin(), s.end(), regex("\\s"), -1), end; for ( ; i != end; ++i ) { string w(i->first, i->second); cout << w << endl; sregex_token_iterator j(w.begin(), w.end(), regex("/"), -1); for ( ; j != end; ++j ) { cout << string(j->first, j->second) << endl; } } }wregex, wsregex_token_iterator を使うと、とりあえず多バイト文字が扱える。
<http://karlmicha.googlepages.com/lg>
作ってたのとほとんど同じものがあった。
C++でユニコード文字といえば
ICU4C
があるけれど、
・APIが非常にJava的なので、あまり使いたくない(STLと相性が悪い)
・正規化処理等を含んでいるので、単に格納して単なる文字列と同じように使いだけの場合にはオーバースペック
などという問題がある。
そこで vector<short> とか考えたけれど、
入出力とかソートとかそれはそれで用意しなければならない。
Javaと違って、統一interfaceをimplementsしてそれを満たせば終わりというわけじゃないので、
面倒。
実は2バイト文字が格納できて入出力もサポートされていて、
かつSTLに対応済(というかSTLの中にある)の
std::wstring
がある。
std::wstring は言語仕様上、単に、
1文字が8ビットより大きいバージョンの std::string
としか定義されていない。
文字長とか文字集合とか、エンコーディングとか、ソート順序とかは全部処理系依存。
この辺が原因で、ポータビリティがないとされている。
(2007-12-18T22:41:39+0900) : 実際、文字コードの指定方法(名前)に関して、Linux同士でも互換性がない。また、複数のエンコーディングを扱うのも苦手。
その辺はあくまで言語仕様の話で、存在する実装では
windows と linux で、wstring = UTF-16文字列
ソートはUTF-16の辞書式らしい。(要出典)
linux では UTF-16 を 32ビットのintに入れて格納しているので、メモリはかなり食う。
wstring の作成は
・処理系がlocaleを持っている
・ソースコードが locale のエンコーディングで書かれている
・扱うデータが locale のエンコーディングで書かれているものだけ
という前提だったら、
std::wstring s;
std::wcin >> s;
という感じでやれる。
このとき、cinを混在させるとなんかややこしいことになった気がするので注意。
最初を適当に決めて、残りを再帰で均等に。
頭の悪いアルゴリズムなので、計算量とかスタックとかがいろいろ大変なことになっている。
#include <iostream> #include <list> #include <iterator> #include <locale> #include <cassert> using namespace std; pair<list<wstring>,size_t> divid_len(size_t num, const wchar_t* str, size_t len) { if ( num == 1 ) { for ( ; ; ++len ) { if ( *(str+len) == L'\0' ) { list<wstring> l; l.push_back(wstring(str,len)); return make_pair(l, len); } } } else { for ( ; ; ++len ) { pair<list<wstring>, size_t> other = divid_len(num - 1, str + len, len); if ( abs(static_cast<long>(other.second - len)) <= 1 ) { list<wstring>& l = other.first; l.push_front(wstring(str,len)); return make_pair(other.first, max(len, other.second)); } } assert(false); } } list<wstring> divid(size_t size, const wchar_t* str) { return divid_len(size, str, 0).first; } int main() { locale::global(locale("")); const wchar_t* sample = L"ゆめよりもはかなき世のなかをなげきわびつゝあかしくらすほどに四月十よひにもなりぬれば木のしたくらがりもてゆく"; list<wstring> ans; ans = divid(4, sample); copy(ans.begin(), ans.end(), ostream_iterator<wstring, wchar_t>(wcout, L"\n")); ans = divid(5, sample); copy(ans.begin(), ans.end(), ostream_iterator<wstring, wchar_t>(wcout, L"\n")); ans = divid(6, sample); copy(ans.begin(), ans.end(), ostream_iterator<wstring, wchar_t>(wcout, L"\n")); return 0; }
<http://gcc.gnu.org/bugs.html#nonbugs_c>
#include <iostream> class cmplx { public: double x; double y; double& real; double& imaginary; public: cmplx(double _x, double _y) : x(_x), y(_y), real(_x), imaginary(_y) {} }; int main(int argc, char** argv) { cmplx c(0.1, 0.1); std::cout << c.real << "+i" << c.imaginary << std::endl; }
#include <iostream> class cmplx_simple { public: long double x; long double y; public: cmplx_simple(long double _x, long double _y) : x(_x), y(_y) {} }; class cmplx { public: long double x; long double y; mutable long double& real; mutable long double& imaginary; public: cmplx(long double _x, long double _y) : x(_x), y(_y), real(x), imaginary(y) {} }; int main(int argc, char** argv) { cmplx_simple x(10.0, 10.0); cmplx c(0.1, 0.1); std::cout << sizeof(x) << std::endl; std::cout << sizeof(c) << std::endl; std::cout << c.real << "+i" << c.imaginary << std::endl; c.x = 0.2; c.y = 0.3; std::cout << c.real << "+i" << c.imaginary << std::endl; std::cout << &c.real << " " << &c.x << std::endl; }
Javaでいうところの
public class Foo {
public Foo(String s) {
...
}
public Foo(SomeClass x) {
this(x.toString());
}
がやりたいのですが、
class Foo {
Foo(string s) {
...
}
Foo(int x) {
Foo(x + "");
}
}
だと
→ 共通部分を関数にしてください。
[10.3] How can I make a constructor call another constructor as a primitive? -- No way.
#include <vector> #include <iostream> using namespace std; int main() { vector<vector<double> > table(2, vector<double>(2)); table[0][0] = 0.1; table[0][1] = 0.2; table[1][0] = 0.3; table[1][1] = 0.4; for ( vector<vector<double> >::iterator i = table.begin(), e = table.end(); i != e; ++i ) { for ( vector<double>::iterator j = i->begin(), f = i->end(); j != f; ++j ) { cout << *j << endl; } } }
<http://www.nesugi.net/hiki/?swig%A4%CE%BB%C8%A4%A4%CA%FD%A4%CE%A5%E1%A5%E2%BD%F1%A4%AD>
1. moduleにしたいプログラムのsource(*.cppとか)を持ってくる
2. cppファイル毎に*.iを書く ← これがswig語
3. swigコマンドで*.iを各スクリプト言語用のwrapper(c++で書かれてる)に変換
4. Makefile.PLやextconf.rbのような、スクリプト言語用のMakefileの元になるファイルを書く
5. 通常のモジュールと同じようにmakeする
関数ポインタはない。
→ interface 経由で”関数”を持つクラスのシングルトンインスタンスを渡す。
リンクはしなくていい。
ただし、ライブラリを使うプログラムを実行するときに、
ライブラリがある場所にパスを通す必要がある。
java -cp lib:. Main
→ 少なくとも、. は CLASSPATH に入れておくべき
ArrayList は add しないとサイズが増えない。
→ 自動的に fill されることがない
generics は template ではない。
Map<K,V> で、
K.equals の引数は Object です。
コンパイル時に型情報は消されます。
Map の契約は要素型に equals(Object) 、 hashCode(void) メソッドの妥当な実装を要求する。
→ annotation
@Override public boolean equals(Object o){ ... }
<http://mi.eng.cam.ac.uk/~er258/code/fp_template.html>
ふつうにできるのを知ってショックでした。
以前、それらしく書いてみたらコンパイルエラーだったので、
できないと思い込んでいた。
// パラメータとして型を渡す template class template< typename T > class T0 {}; // パラメータとして1階テンプレートクラスを渡す template class template< template<typename> class T > class T1 {}; // パラメータとして2階テンプレートクラスを渡す template class template< template<template<typename> class> class T > class T2 {}; // パラメータとしてテンプレートと型を受け取り、テンプレート適用をする template<template<typename> class TMPL, typename T> class ApplyTmpl { public: typedef TMPL<T> type; type constructor() { return type(); } type* newInstance() { return new type(); } }; // パラメータとして値を渡す関数 int f0(int x) { return 0; } // パラメータとして1階関数を渡す関数 int f1(int (*x)(int)) { return 0; } // パラメータとして2階関数を渡す関数 int f2(int (*x)(int (*)(int))) { return 0; } // パラメータとして関数と値を受け取り、関数適用をする int apply_func(int (*x)(int), int y) { return x(y); }
<http://gcc.gnu.org/onlinedocs/gcc-4.0.3/gcc/Optimize-Options.html#index-fstrict_002daliasing-511>
int i = 10; float f = *( (int*)&i );は移植性が低いだけでなく、GCC4の最適化
-O2
-O1 -fstrict-aliasing -fschedule-insns
によって意味が変わる。
訂正版
union int_float { int as_int; float as_float; } int_float x; int i = 10; x.as_int = i; float f = x.as_float;
<http://doc.trolltech.com/4.2/tutorial.html>
一見 Java awt, swing と似ている。
SIGNAL & SLOT のイベント処理のところは違うけれど。
qmake -project
qmake
make
<http://www.msc.cs.gunma-u.ac.jp/~tanaka/boost/BGL.html>
<http://www.icce.rug.nl/documents/cplusplus/cplusplus03.html#an208>
x = ~x;
x = compl x;
x = x ^ 0;
x = x xor 0;
<http://boost.org/doc/html/boost_staticassert.html>
コンパイル時に、型変数の値チェックとかできる。
かなり便利かも。
#include <iterator> #include <boost/static_assert.hpp> #include <boost/type_traits.hpp> template <class RandomAccessIterator > RandomAccessIterator foo(RandomAccessIterator from, RandomAccessIterator to) { // this template can only be used with // random access iterators... typedef typename std::iterator_traits< RandomAccessIterator >::iterator_category cat; BOOST_STATIC_ASSERT((boost::is_convertible<cat, const std::random_access_iterator_tag&>::value)); // // detail goes here... return from; }
任意の型のハッシュ値を計算する枠組みは?
Java は Object.hashCode() があるので、
ユーザー定義のクラスでもそれにのっとればいい。
C++ では boost::hash<typename T> が凖・標準。
http://www.boost.org/doc/html/hash.html
via http://d.hatena.ne.jp/y-hamigaki/20060826