No Such Blog or Diary

«Prev || 1 | 2 | 3 |...| 12 | 13 | 14 || Next»

gcc の < regex > の正規表現の不思議

以下のプログラムは "G" という文字列が "A|T|G" という正規表現にマッチするかどうかを調べるもので,当然マッチするので ret=1 が期待する出力となる.

#include <regex>
#include <iostream>
using namespace std;
using namespace std::regex_constants;
 
int main(){
  regex r("A|T|G");
  string s("G");
  bool ret=regex_match(s,r);
  cerr << "ret=" << ret << endl;
}

が,いくつか試した gcc で出力が ret=1 になったのは svn 上の gcc (4.9.0 experimental) だけだった.Ubuntu 12.04 amd64 でソースからコンパイルした 4.8.2 でも ret=0 で,他に同Ubuntu の 4.6系 とソースからコンパイルした 4.7.2 もダメで,cygwin の 4.8.1 もダメだった.

Visual Studio では ret=1 になったらしい.Boost は大丈夫らしい.Mac の gcc のどれかも上の単純な例では大丈夫だったらしい.

どうも | で3つ以上つながると狂うらしい.まあ,Is gcc4.7 buggy about regular expressions? とかを見る限りだいぶ前からこの状況らしく,そもそも gcc (libstdc++) の regex は不完全であると.だがしかし,"A|T|G" とかいうレベルの単純な正規表現でもダメとか言うレベルの不完全さとか誰も想像できん.驚いた.

C++ の文字列リテラルを型に変換してメタプログラミングする方法

Using strings in C++ template metaprograms という記事を見つけた.

基本は「定数配列の定数要素アクセスは定数である」という仕様を使うのね.長さの違う文字列に効率的に対応するために,最長文字列長を決めといて,その文字列長に対応するマクロをプリプロセッサの繰り返しで作っておいて,短い奴に対応するために要素アクセスを constexpr な関数で条件付きにしてあると.

うーん.長さ制限をなくせる手法があると完璧なのだけど,無理かね.文字列リテラルの文字列長はコンパイル時には取れるけれどプリプロセスの時点では取れないか.

閑話休題.

constexpr な関数が普通の関数としてコンパイルできること,とかいう条件が邪魔だな…… コレのせいで constexpr な関数の引数をテンプレート引数に入れることができない.例えその関数が常に定数に対してしか使われないとしても.

定数に対してしか使えない関数を定義できる枠組みがあると便利そうだけどコンパイラが大変そうだなぁ.

多次元配列とポインタのポインタと

時々「配列とポインタは同一視出来る」という説明を聞くのだけど,これって良い説明なのか悪い説明なのかよく分からない.特に,多次元の配列の解説と同時にこの説明があるのはどうなのかなぁとか疑問に思う.1次元の配列を扱う範囲に置いては特に文句はないのだけど.

多次元配列の解説においては,「多次元配列=ポインタのポインタ」という説明になる.仮に float c[10][20] という配列と float **d というポインタがあった場合,この説明では c = d とした以降は c と d がプログラム中で同一に扱えることになる.が,実際には c と d はインクリメントとかデリファレンスの挙動とかが違い,同一視すると痛い目を見る.正しくは,c は 20要素の float 配列のポインタ(float (*)[20]と書くのか?)と同一視出来る程度であって float ** とは別物と.

ということで,下のプログラムを動かすと c と d が別物だとよく分かる.c と e は同じ挙動.

main(){
  float c[10][20], **d, (*e)[20];
  d = c;
  e = c;
  printf("%p %p %p\n", c, d, e);
  printf("%p %p %p\n", c+1, d+1, e+1);
  printf("%d %d %d\n", c == *c, d==*d, e==*e);
}

結果は以下の通り.

0x7fff7bca9320 0x7fff7bca9320 0x7fff7bca9320
0x7fff7bca9370 0x7fff7bca9328 0x7fff7bca9370
1 0 1

C言語のクイズ

適当なXを持ってきて以下の二つの文が等価でないことを示せ:

X += e;
X = X + e;

まあ,副作用のある関数 f の呼び出しを X に上手く入れられれば等価でないことを言えるのだけど,単純に X を f() にしただけでは左辺値じゃないと怒られる.何かでくるんで左辺値にすればオッケー.

f()を含んだ左辺値になる式は色々あるけれど,例えば配列へのアクセス a[f()] なんてのはその候補.さて,では,そのような式の中で最小のものは何なんだろうか? ゴルフする人間としては気になる.

で,さっき思いついたけど,ポインタを返す副作用のある関数 f を持ってきて X に *f() を入れれば以下の二つの文は等価じゃない.

 *f() += e;
 *f() = *f() + e;

これが最小の解なのだろうか?

lastprivate の罠

OpenMP の parallel for でローカルの値を外に持ち出す指定のひとつ lastprivate の意味を間違って覚えていると罠にハマる.last private であって last assigned private ではなかった.

下のようなプログラムを書いた.いつでも 2 が表示されて欲しい,つまり,lastprivate指定の変数は最後に代入された値を外に持ち出してくれると期待していた.

#include <omp.h>
#include <iostream>
 
struct mystruct {
  int f;
  mystruct() : f(-1) {}
  mystruct(int f) : f(f) {}
};
 
int main(int argc, char *argv[])
{
  mystruct ms(1);
#pragma omp parallel for lastprivate(ms)
  for(int i = 0; i < 4; i++) {
    if(i == 2) {
      mystruct msi(2);
      ms = msi;
    }
  }
  std::cout << ms.f << std::endl;  
  return 0;
}

が,実行してみると以下のような結果になった.

> OMP_NUM_THREADS=1 ./lastprivate 
2
> OMP_NUM_THREADS=2 ./lastprivate 
2
> OMP_NUM_THREADS=3 ./lastprivate 
2
> OMP_NUM_THREADS=4 ./lastprivate 
-1

何かというと,lastprivate指定の変数は最後のプロセスの持つローカルな値をグローバルにコピーしてループを終了する,という仕組みであったと.確かにOpenMPの仕様にはそう書いてあるし,逐次実行時に最後に実行される反復で値を代入しない場合にはオブジェクトの初期値になっちゃうよ,とも書いてある.上のプログラムでの最終反復(i = 3)では変数 ms に値が代入されないため,その初期値(-1)になってループ終了と.

うーん,find みたいに最後に条件を満たすインデックスを探すとかいうループすらもOpenMPだと簡単に書けないのか… (FORTRAN なら MAX での reduction 指定ができるので可能だけど).

lastassignedprivate とかいうディレクティブの方が使い勝手が良いと思うのは気のせいだろうか? 変数についてフラグ一個持てば直ぐに実装できるのに… とりあえず OpenMP の reduction の制限がきつすぎるのが良くない.

std::result_of 便利だなぁ

引数に関数オブジェクトを取るテンプレート関数の戻り値の型が,その引数の関数オブジェクトの戻り値の型に依存することはしばしばある(変なギミックの付いたライブラリとか書くと特に).関数プログラミングよろしく結果のオブジェクトを作って返すような関数を作っているときには戻り値の型をどうにか推論しないといけない.

んで,どうやって推論したもんかなぁとか思ってたら c++0x なら std::result_of が使えることを発見.これ使うと,例えば vector の要素に関数適用して新しい vector 返すとかいう関数がこう書ける(vector 返すとかバカなプログラムだなぁ.例だからいいか.):

template <typename F, typename A>
std::vector<typename std::result_of<F(A)>::type>
map(const F& f, const std::vector<A> &v)
{
  std::vector<typename std::result_of<F(A)>::type> r;
  for(auto it = v.begin(); it != v.end(); it++)
    r.push_back(f(*it));
  return r;
}

std::result_of 無しだと関数オブジェクトに戻り値の型をtypedefさせるかテンプレート引数増やして明示してもらうかしないとならんと思うので std::result_of は結構便利なんじゃないかと思った今日この頃.コードがすっきりしているかどうかは判断が難しいけど.

«Prev || 1 | 2 | 3 |...| 12 | 13 | 14 || Next»
Search
Feeds

Page Top