2013-12-08

neobundle.vimのインストール方法

Shougo/neobundle.vimは、Vimプラグインのインストールと管理のためのプラグインである。

インストール方法

まず、GitHubから最新版を引っ張ってくる。私の今使っているネットワークの都合上か、sshでcloneできなかったので、httpsを使う。

$ mkdir -p ~/.vim/bundle
$ git clone https://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim

次に.vimrcに設定をする。最小限の例は以下のようになる。

if has('vim_starting')
  set runtimepath+=~/.vim/bundle/neobundle.vim/
endif

call neobundle#rc(expand('~/.vim/bundle/'))

" Let NeoBundle manage NeoBundle
NeoBundleFetch 'Shougo/neobundle.vim'

" add plugins

filetype plugin on

NeoBundleCheck

neobundleにプラグインを管理させるのはとても簡単。.vimrcに追加していく。特に、プラグインがgithubで公開されている場合、ユーザー名とレポジトリ名を指定するだけでいい。

" install wandbox-vim
NeoBundle 'rhysd/wandbox-vim'

必要なだけ書いたら、vimを起動して、

:NeoBundleInstall

すればよい。

アップデートしたくなったら、

:NeoBundleUpdate

するだけでいい。

GitHub以外の場合、gitのURLを指定することができる。また、subversionもサポートしているようだ。

それにしても、よくVimプラグインでこれをやるものだ。これまで、@ShougoMatsu さんは、Vimの頭のおかしい人だと思っていたが、なんとVimの変態だったとは。

CとC++の違い: プリプロセッサー編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

C++では、__STDC__については規定されていない。

__STDC__は、C言語の実装において定義されるプリプロセッサーマクロである。C++はC言語ではないので、このマクロについてC++の標準規格上、なにか規定することはできない。

そのため、__STDC__は、その値と、定義されるかどうかも含めて、何も規定されていない。C++実装はそれぞれ独自に、このマクロの扱いを決めることになる。

しかし、C++はC言語の拡張として発展したという歴史があり、100%ではないものの互換性があるという事情もある。既存のCコードに、このプリプロセッサーマクロに依存したコードがある場合、たとえC++と互換性のあるCコードでも、このプリプロセッサーマクロが定義されていないという理由だけでコンパイルできなくなるかもしれない。そのために、このようなプリプロセッサーは、C言語との互換性が問題になる場合、定義しておきたい。しかしそれは、ある意味嘘をつくことになる。しかし、そもそもそのようなプリプロセッサーに依存するようなCコードの問題もある。

Cプリプロセッサーは滅びるべきなのだ。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-12-07

CとC++の違い: 特別なメンバー関数編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

C++では、暗黙に生成されるコピーコンストラクターとコピー代入演算子は、volatileオブジェクトをコピーできない。

struct S
{
    int i ;
    // C++
    // 暗黙のコピーコンストラクター
    // S( S const & ) ;
    // 暗黙のコピー代入演算子
    // S & operator =( S const & ) ;
} ;

int main()
{
    volatile struct S s = { 0 } ;

    // Cでは合法
    // C++では違法
    struct S s2 = s ;
}

これは、暗黙に生成されるコピーの仮引数の型が、T const &だからだ。強い静的型付けをもつC++だから、このままではvolatileオブジェクトは受け取れない。

volatileの扱いは色々と難しく、C++では色々と議論された。

暗黙のコピーを、const volatile T &とする案は、最適化の妨げになるという理由で却下された。三種類のCV修飾されたコピーを暗黙に生成するという案は、とても複雑になり、予期しない問題を生むだろうという理由で却下された。結局、このようなコード例は少ないだろうからということで、この点ではCとは非互換になることを決定した。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-12-06

CとC++の違い: クラス編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

今回は、クラス編だ。C++ではクラスを導入したせいで、C言語の構造体とは少し違ったスコープのルールになっている。

C++では、クラス宣言はクラス名をスコープに持ち込む。C言語ではクラス名を持ち込まないし、外部スコープの名前を隠すこともない。

int x[99] ; // #1

void f()
{
    struct x { int i ; } ; // #2

    // Cでは#1のサイズ
    // C++では#2のサイズ
    sizeof( x ) ;
}

これはなぜかというと、C言語では、宣言した構造体名は必ず、structキーワードをつけて使うからだ。C++では、基本型とユーザー定義型の文法に違いを持たせたくないため、クラス名だけで使えるようにしている。そのため、クラス名がスコープに導入される。

C++では、int型のビットフィールドの型は符号付きである。Cでは符号は実装依存である。

int型のビットフィールドの符号を実装依存にするのは、テンプレートの実体化のさいに問題になる。一貫性を保つため、非依存名でも、符号つきになるように、実装の自由度を狭めた。

いくらビットフィールドとはいえ、"int"なのに、符号付きかどうか実装依存というCの定義は不思議だ。

C++では、ネストされたクラス名の属するスコープは、直前の外側のクラススコープである。Cでは、直前の外側のクラスが属するスコープである。

struct Outer
{
    struct Inner { } ;
} ;

// Cでは合法
// C++では違法
struct Inner i ;

C言語はわけがわからない。

どうやら、当時のC言語における構造体というのは、そもそもスコープがどうというものではなかったようだ。そもそも、名前もtypedef名で与えるコードが一般的だったようだし、全然別の言語なのだろう。

C++では、メンバー関数を導入したことにより、クラスは厳格にスコープを持たなくてはならなくなった。それがこの違いを生んだのだろう。それにしても、Cは汚い。

C++では、クラス名ですでにtypedef名が使われた場合、そのtypedef名が再宣言されてはならない。

typedef int I ;

struct S
{
    I i ; // typedef名をすでに使う

    // Cでは合法
    // C++では違法
    int I ;
} ;

たしかこれはD&Eにも書いてあった内容のはずだ。クラスはその完全な定義が明らかになった後に、再び銭湯から解釈した時に、メンバー名の意味が変わってはならないというルールだ。それにしても、Cは汚い。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

OCNモバイルONEのレビュー

好意で、OCNモバイルONEのSIMカードをしばらく貸してもらうことになった。

今回貸してもらったSIMカードの契約内容は、月々1980円で、帯域が500kbps、転送量制限が月あたり7GBで、転送量を超過すると、帯域が200kbpsに制限されるというものだ。

OCN モバイル ONE | OCN プロバイダ(インターネット接続)

何故か公式Webサイトには負の広告効果を発生させそうなデブ女が怪訝そうな顔をしてSIMカードをつまんでいるが、この女がSIMカードの意味を理解しているとは思えない。一体、世の広告業界は何を考えているのだろうか。特に英語力で有名でもない人間に英会話教室の広告をさせたり、特に技術力に優れていると定評のあるわけでもない人間にコンピューターやソフトウェアの広告をさせたりしている。

試みに、筆者が、かければアキバ系の彼でもジャニ系に変身できるというあの伝説のサングラスの広告に出ている場面を想像せよ。およそあり得べからざる光景である。およそジャニ系を名乗るには、髪をだらしなく生やした上で寝ぐせをたっぷりとつけねばならないのである。機能美を何よりも優先する筆者は、頭髪などもとより剃りあげている。頭髪などは本来人間に不要の体毛である。人間がいまだわずかに体毛を維持しているのは、単にヒトが進化の途中であるに過ぎないのだ。

これまでに使っていた、DTIのServerMan SIM LTEは、帯域が150kbps、転送量制限がなし、強制画像劣化圧縮プロクシというものだった。

ServersMan SIM LTE:【dream.jp】

本の虫: 100kbpsで閲覧できるWebサイト、できないWebサイト

この記事を書いた後も色々と試したのだが、このDTIの画像の劣化圧縮のためのプロクシは、かなり厄介だ。というのも、このプロクシが間にあるおかげで、ものすごい遅延が発生する。しかも、このプロクシサーバー、かなり頻繁に不安定になり、コネクションははれるが、一切受信できない状態に陥る。例えば、昨日は一日中、使うことができなかった。

そう、DTIの格安SIMでよく発生している問題は、帯域ではなく、DTIのクソプロクシの問題だと思うのだ。

OCNモバイルONEには、そのような罠はない。500kbpsとは帯域が5倍であるが、帯域以上に、このクソプロクシがなくなったというのが大きい。これで、十分に待てば、どのようなWebサイトでも閲覧できるようになる。

たとえば、通常のGMailのWeb上のUIも少し待てば表示されるし、Google Mapsも少し読み込みに時間がかかるが使える。さらに、Street Viewまで使えるのだ。

もちろん、筆者のコンピューターはOSから上のソフトウェアはすべて自由ソフトウェアのみで構成されているので、Flash Playerは入れていない。同じく貰い物のこのラップトップは、IntelのHD3000を使っており、公式に自由なソフトウェアスタックを使ったドライバーが提供されていて、ドライバー環境はとても綺麗なのだ。Google MapsのStreet viewは、GPU支援があるのか、それともChromiumのソフトウェアエミュレーションかはしらないが、WebGLを使うことで、パフォーマンス上全く問題なく利用できる。

他にも、pixivを画像の超絶劣化なしに閲覧できるし、今は吉田寮にいるので検証できないが(とはいっても、今筆者が座っているこたつの周りにはエロ画集とかも転がっているので、できない理由もないのだが)、おそらくxvideosも問題なく閲覧できることであろう。特に、今回は技術的に面白いこともないので、xvideosは検証しない。特に動かないであろう理由もないからだ。

しかし、今は無線によるインターネット接続が本当にお手軽になってきた。

CRTPと仮想関数呼び出しの比較

Eli Bendersky's website » The cost of dynamic (virtual calls) vs. static (CRTP) dispatch in C++

CRTPを使えば、コンパイル時に決定できるような派生クラスの関数呼び出しは、仮想関数呼び出しで実行時に解決しなくても、直接呼び出せることになり、仮想関数呼び出しを省略できる。このコストはいかほどか。

アーキテクチャーによっては6倍になるそうだ。

X11の究極の互換性の実証

The Resistor Network: A Testament to X11 Backwards Compatibility

Hewlett Packard 1670A Deep Memory Logic Analyzerという1992年のマシンに、Xサーバーに接続できる機能があるので、Linux Mint 15とe17で試してみたところ、なんと問題なく動いたそうだ。

なんと言うプロトコルの後方互換性。

2013-12-05

CとC++の違い: 宣言編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

今日は、宣言の違いを解説する。

C++では、staticやexternキーワードは、オブジェクトの宣言にのみ使用できる。型の宣言に指定することはできない。Cでは、型の宣言に指定することもできた。その場合、単に無視される。

// Cでは無視される
// C++ではエラー
static struct S
{
    int i ;
} ;

C言語では、合法ではあるが、単に無視されていた文法を、禁止しただけだ。このようなコードはまず書かれていないだろうから、特に問題にはならないだろう。

C++では、同一のスコープ内で、typedef名とクラス名を重複して宣言することができない(ただし、同名のクラスへのtypedef名を除く)。Cでは、構造体名と異なるエンティティで同名のtypedef名を宣言できる

// OK in C and C++
typedef struct S { } S ;

// CではOK
// C++ではエラー
struct name { } ;
typedef int name ; 

なぜC言語ではこれが許されていたかというと、C言語では、構造体は必ずstructキーワードを使う必要があったからだ。

struct S { } ;

// Cではstructキーワードが必須
struct S s ;

C++では、基本型とユーザー定義型を、なるべく区別なく使えるようにしようという観点から、このようなstructキーワードの使用の省略を許した。そのため、クラス名はスコープ内で重複することができなくなり、このような変更が必要となった。

C++ではconstなオブジェクトは必ず初期化されなければならない。Cでは、初期化しなくてもよい。

// well-formed in C
// ill-formed in C++
const int object ;

constオブジェクトは、変更できないわけだ。したがって、constオブジェクトが有益な値をとるには、必ず初期化されなければならない。したがって、C++ではconstは初期化しなければならない。

そもそも、constを導入したのはC++が先で、Cが後から追随したはずだ。C言語というのは不思議な劣化があるものだ。

C++では、暗黙のintを廃止

あー、暗黙のint、あの忌まわしき機能を解説することになるとは、私はよほど前世で悪業を重ねてきたに違いない。

f( const x )
{
    const y = x ;
}

このようなコードが、「暗黙のint」というタイプするのさえ恐ろしい機能によって、Cでは合法になる。関数fの型はint( int )で、変数yの型もintだ。

C++では、autoキーワードをストレージクラス指定子として使えなくなった。

Cでは、autoキーワードは、ローカル変数を自動ストレージ上に確保するための指定子だった

void f()
{
    auto int x = 0 ;
}

ただし、古今のC言語のコードで、autoキーワードを教科書以外で使っているのを見たことがない。なぜならば、ローカル変数はデフォルトで自動ストレージ上に確保されるのだから、わざわざつける必要がないからだ。

C++では、キーワードを再利用して、初期化子の式から変数の型を推定する新機能として生まれ変わった。

auto x = 0 ; // int

C++でこのような破壊的変更を行えたのも、結局、誰もautoキーワードなんか使っていなかったからだ。

C++では、enum型のオブジェクトには、同じenum型のenumeratorしか代入できない。Cでは、どんな整数型でも代入できる。

// well-formed in C
// ill-formed in C++
enum color { Red, Green, Blue } ;
enum color = 1 ;

強い静的型付けを持たないCはどうしようもない。

C++では、enumeratorの型はその属するenum型。Cでは、int型

enum E { value } ;

// C++における式の型はE
// Cにおける式の型はint
value ;

強い静的型付けを持たないCは悲惨だ。

次回は、宣言子の違いについて解説する。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-12-04

CとC++の違い:式編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

今回は式編

C++には関数の暗黙宣言がない

昔のC言語には、関数の暗黙宣言があり、関数名は宣言しなくても使うことができた。C++では、名前は宣言しなければ使えない。

void f()
{
   g() ; // エラー、gは宣言されていない
}

C++では、型は宣言の中で定義しなければならない。C言語ではsizeof演算子やキャスト式の中で定義することもできた。

// Cでは合法
// C++では違法
size_t size = sizeof( struct { int i ; } ) ;

条件式、代入式、コンマ式の結果がlvalueになることがある

C++では、リファレンスにより、関数がlvalueを返すこともできる。

これは、lvalueからrvalueへの変換をあてにしていたCコードを壊すおそれがある。例えば以下のようなコードの挙動が異なる。

char arr[100] ;

// C++では結果は100
// Cでは結果はsizeof(char *)
sizeof( 0, arr ) ;

まあ、この挙動に依存したコードはまれだろう。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

C++の歴史のスライド資料をGitHubで公開

C++の歴史について話してくれという依頼があったので、そのためのスライド資料を書いた。

依頼主からは独立した内容で、C++の歴史や標準化委員会の実情を書いていて面白いと思うので、GitHubで公開する。

GitHub: EzoeRyou/cpp-history

GitHub Pages: C++の歴史

まだまだ加筆するかも知れない。

今回の依頼主の講演は非公開だが、いずれ個人的に勉強会を開いて、このスライドを使った発表もしたいものだ。

結局、自由なものに金をだすというのは、こういうものを作るのに金を出すということになるのだろう。金を出さなくても誰かがいずれ書くかも知れないが、それは数百年後かも知れない。今欲しければ、金を出して書ける者に書いてもらうのが手っ取り早い。

2013-12-02

CとC++の違い: 標準型変換編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

今回は標準型変換の違い。

C++では、void *から任意のポインター型への変換には明示的なキャストが必要

C言語では、void *型は特殊な型で、任意の型へのポインター型をvoid *型に暗黙に型変換できるし、またvoid *型から任意の型へのポインター型に暗黙に型変換できた。

// Cコード

int * ptr = NULL ;
void * v = ptr ; // OK
int * i = v ; // OK

C++では、void *への変換は暗黙にできるが、void *から他の型への変換は、明示的なキャストが必要になった。

// C++コード

int * ptr = nullptr ;
void * v = ptr ; // OK
int * i = static_cast< int * >( v ) ;

明日も、宣伝のために式の変更点を解説する。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-11-30

100kbpsで閲覧できるWebサイト、できないWebサイト

今、私が常時使えるネット回線は、DTIの提供する格安のSIMカードを利用したLTE経由のものだ。利用料金は月々490円+ユニバーサルサービス料3円となっている。

とてつもなく格安だが、極端な制限がある。帯域が100kbps、今は実験的に150kbpsに制限されているということだ。転送量制限はないのだが、この帯域は、2013年にはなかなかに厳しい。

私は、まだ56Kbpsのアナログモデムの頃からインターネットを利用しているが、もはや最低でも数Mbpsは当たり前になったこの時代に、100kbpsは、結構難しいところもある。使えるかどうかは、Webサイトにより異なる。

今、風邪をひいて体調が悪く、外に出れないのを幸いに、この低帯域でできることを試してみることにした。

まず、まともに閲覧できないWebサイトだ。

例えば、GMailのような、巨大なJavaScriptでできたプログラムで、常にサーバーと通信しているようなWebサービスは、かなり使いづらい。GMailのWeb UIには遅いネットワーク版もあるが、これでも100kbpsでは使いにくい。

結局、問題は帯域なのだ。あらゆる通信は100kbpsの帯域を通らなければならないのが問題なのだ。これら、数百キロバイトから数メガバイトもあるような巨大なJavaScriptプログラムをダウンロードするだけで時間がかかる。また、それだけではなく、そのJavaScriptプログラムは、さらにサーバーと通信を行う。

単に時間がかかるというだけではない。詳しい理由はわからないが、通常のGMailはたいてい、いくら待っても使えない。何度かリロードしてようやく使えるようになる。思うに、HTTPやHTTPSプロトコルを使い、複数のファイルを同時にダウンロードしようと試み、それがすべて狭い100kbpsのネットワークを通過しなければならないため、どのファイルもダウンロードが完了せずに延々とちびちび読み込み続けているのではないかと思う。通常のGMailは極端な低帯域は考慮していないようで、そういう場合に、いくら待ち続けようとも、延々と読み込み中の画面を表示し続ける。何度かリロードすると使えるようになるというのは、あるいはファイルの一部がキャッシュされてダウンロードしなくても済むため、並行ダウンロードが減少し、GMailのJavaScriptプログラムでも動く程度の時間でダウンロードできるようになるのではないか。あるいは、あまりに時間がかかりすぎるため、JavaScriptプログラムかブラウザーのどちらかがダウンロードを諦めたのか。

はたまたあるいは、これらのサイトがHTTPSプロトコルを使っているからなのかもしれない。あまりに低帯域でHTTPSプロトコルを使うとこういう問題に出くわすのかも知れない。

ひとたびGMailの巨大なJavaScriptプログラムが動きさえすれば、あとは快適に使えるのだが。

TwitterのWebサイト上のUIも、同じ問題を抱えている。Twitterのページを読み込む際に、他にも、別のページやファイルなどのダウンロードが発生している場合、たとえ別のページやファイルのダウンロードが終わって、帯域が空いても、読み込み中のまま一向に進まないことがある。

Googleの検索も、同じ問題を抱えている。

YouTubeは、動画の再生はともかく、極小のサムネイルの表示まで遅い。

では、まともに閲覧できるWebサイトは何か。

基本的に、テキストを主体とし、JavaScriptで高度で頻繁な通信を行っていないようなページは、問題なく表示できる。Hacker Newsも問題ない。[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッも問題ない。

意外なところでは、pixiv.netが快適に閲覧できるということだ。サムネイルの表示も十分に速い。もちろん、100kbpsなので、個々の画像をダウンロードして表示するのにはそれなりに時間がかるが、このサムネイル画像の速さは大したものだ。また、pixivはHTTPSを使っていないことも影響しているのかも知れない。しかし、それをいえばYouTubeだってHTTPSではないのは同じだ。しかも、pixiv以上に小さいサムネイル画像の表示が遅い。

あるいは、YouTubeを閲覧する利用者のネットワークは、そもそもそれなりに広い帯域が必要であろうから、手描き画像に特化したpixivほど低帯域ユーザーの需要がないのかも知れぬ。需要がなければ供給もない。Yahooが既存の広告媒体よりは安いが、ネット広告としては高すぎるのに、無知な広告主によって払われる多額の広告料にあぐらをかいて技術革新を怠り、Googleに追いぬかれたように、需要は重要である。

はて・・・低帯域ユーザーでも変わらず需要があるものとなると・・・

深い技術的好奇心の念に駆られた筆者は、あくまで知的探究心のために、xvideos.comを閲覧した。

Lo and behold!

すると見よ! わずか100kbpsの低帯域だというのに、YouTubeよりはるかに大きな、しかも大量のサムネイル画像が一瞬にして表示され、マウスカーソルを当てるとコマ送りまでするではないか。

筆者は慄然とした。今にして始めて芸道の深淵を覗き得た心地であった。

誠に残念ながら、OSから上は自由なソフトウェアのみで構成された筆者のコンピューター環境にはFlash Playerがなく、したがって、100kbpsのネットワーク越しに動画を再生できるかという肝心の主要機能に関しては、技術上非常に興味はあるものの、遺憾ながら検証できなかった。ただ、おそらくうまくやるのではないかと思う。

無論、これは今に始まった話ではない。エロサイトの動画プレイヤーの方が、YouTubeよりよっぽど優れているというのは、昔から言われていたことだ。

本の虫: なぜエロサイトの動画プレイヤーはYouTubeより高機能なのか

このようなエロサイトは、厳しい競争にさらされている。収益をあげるためには、できるだけ多くの閲覧者を得る必要がある。広告収入を得るにしても、課金収入を得るにしても、とにかく大量の閲覧者を集めなければならない。そのためには、低帯域ユーザーが閲覧できないということは、取り逃すことのできない機会損失なのだろう。それにしても・・・

論語に言う、いまだに色を好むが如きものを見ざるとはこのことか。

追記:pixiv.netとxvideos.comが快適な件について、少し事情が異なった。

ご注意事項|ServersMan SIM LTE:【dream.jp】

DTIの格安SIMカードを経由してHTTPプロトコルによりダウンロードされる、画像フォーマットのうち、JPG, GIF, PNGは、DTI側で自動的に劣化圧縮される。

xvideos.comで確認したときは、まあ、エロサイトだしこんなものかと思っていたのだが、さすがに引越し前まで毎日見ていたpixivは気がついた。

何のことはない。HTTPSプロトコルが遅いと感じていたのは、中間で乗っ取りできないからだったのだ。pixivやxvideosが快適に閲覧できたのは、画像を劣化圧縮していたからなのだ。

というわけで、この記事は当初の面白い記述から遠ざかってしまった。この記事を書くときは、「やはりエロ需要の力は偉大だ」という、あからさまに面白い結果になったと早合点して、そのように面白おかしく書いたのだが、現実はそれほど面白くはなかった。残念。

2013-11-29

Clangで-std=c++1yがいまだに使いにくい事情

ClangがC++14の機能完全に到達したことはすでに述べた。これはつまり、最新版のClangで、-std=c++1yを指定すると、現在のC++のドラフト規格の、動く実装が手に入るということだ。

これは素晴らしいことだ。

しかし、いざ実際にUbuntu 13.10でClangのSVN HEADを自前ビルドして使ってみようとすると、以下のようなエラーが表示される。

/usr/include/c++/v1/cstdio:156:9: error: no member named 'gets' in the global namespace

ヘッダーファイルを一切includeしなくても、このエラーは表示されてしまう。

この事情は・・・結構複雑なのだ。

C++14では、Cの標準ライブラリは、C11のものに合わせられた。C11の標準ライブラリでは、とうとうあの忌まわしき太古の呪いである、getsを廃止した。廃止である。非推奨ではない。C11では、もはやgetsは存在しないのだ。

したがって、C11やC++14モードでコンパイルするには、このgetsを#ifdefで囲むなどして、取り除く対応をしなければならない。

しかし、現行の多くのGNU/Linuxの安定版ディストロが使っているglibcのバージョンは、まだこの変更に対応していない。

それもそのはずで、C11のgets廃止に対応したglibcを使うには、GCC 4.9が必要なのだ。GCC 4.9は、まだ開発途中で安定リリースされていない。そんなGCCをデフォルトで出荷するGNU/Linuxディストロなどあるはずがない。

GNU/Linuxにおいては、libcのような基本的なライブラリと、C++コンパイラーは密接に関係していて、単にコンパイラーだけを自前ビルドして使うわけにはいかないのだ。

したがって、もし自前ビルドするとなると、ClangとGCC一式を完全に自前ビルドした上で、ライブラリへのパスを自前ビルドのglibcに通すなどしなければならない。おっと、C++標準ライブラリも、libc++を使いたいし、ABIライブラリも悩ましい。これらのコンパイラーとライブラリを正しく配置して正しくパスを通すのは、とても面倒なのだ。

やればできるだろうが、こんな面倒なことはやりたくない。私はおとなしく、GCC 4.9が安定リリースされて、GNU/Linuxディストロで、ソフトウェアがプロの手によってパッケージ化されるのを待つことにする。

とはいっても、とりあえずC++14の新機能を試してみたいものだ。実は、そんなあなたにうってつけのSaaSSがある。

[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ

melponさん、ありがとよ。

なんと、Vim用のプラグインまである。

rhysd/wandbox-vim

Linda_ppさん、ありがとよ。

参考:

Bug 13566 – Glibc should define gets for C++11

Bug 51785 – gets not anymore declared

2013-11-28

12月18日に東京に行きそうな予定

どうやら、12月18日に東京に行く機会がありそうだ。

今回は、表立った発表ではないが、魔導書の記事執筆依頼、数年ぶりにC++の歴史をまともに調べた。といっても、大方はD&EやHOPL2, HOPL3を読み返しただけなのだが。HOPL-3以降の歴史は、現在進行形で私も追っているし、まだ現在のことなので、Stroustrupがまとめるほどではない。ただ、いずれStroustrupの視点でまとめたHOPL-4がでれば、読みたいとは思う。

また、今となっては死んだEC++についても、いい機会なので、最初から最後まで関わっていた人物から、改めて話を聞いた。

その結果は、まだスライド資料として執筆中だが、とりあえず資料だけでも、12月中に公開しておこうと思う。

今のところの予定としては、とりあえず18日は卓球ハウスに泊めてもらい、18日か19日に、誰かと食事にでも行ければと考えている。

CとC++の違い: Basic Concepts編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

C++はCの完全互換ではない。Cのあまり良くない部分は、変更して改良した。ここでは、そのような変更点のうち、互換性に特に問題のあるものを取り上げる。

tentative definitionの有無

C言語には、tentative definitionという機能があった。以下のようなコードが合法になる。

int i ;
int i ; // well-formed in C, ill-formed in C++

C++にはOne Definition Ruleがあるので、このようなコードは違法である。

C言語に存在するtentative definition機能は、定義の後で初期化できるという機能を提供している。

struct X { X * next ; } ;

X a ; // 定義
X b = { &a } ;
X a = { &b } ; // 初期化

C++では、基本型とユーザー定義型で別々の初期化ルールを設けるのを防ぐために、tentative definition機能はCから受け継がなかった。

structにはスコープがある

C++では、structは構造体ではなくクラスであり、新たなスコープを作る。Cではstructは、単なる構造体であり、その名前探索の挙動が異なる。

ただし、通常はこの差を気にする必要はない。

ファイルスコープ内で、const修飾され、extern指定されていない変数は、C++では内部リンケージとなる。Cでは、外部リンケージとなる。

// file1

// Cでは外部リンケージ
// C++では内部リンケージ
const int x = 0 ;
// file2

// Cではfile1のxを指す
// C++は違う
extern const int x ;

C++では、constオブジェクトは、コンパイル時定数となることもあるので、初期化子が必須なこともあるので、このような変更がなされた。

C++では、main関数を再帰的に呼び出すことはできず、アドレスを取得することもできない。

C++では、main関数は特別なものとして認識され、呼び出すことはおろか、アドレスを得ることさえできない。Cでは、そのような制限はない。

C++でこのような制約がある背景事情としては、mainは特別な扱いであるべきで、その実装方法に関して、C++の実装に、通常のような関数として扱えるような制約を持たせたくないというものがあるそうだ。

Cで書かれたmain関数を再帰呼び出ししたりアドレスを得たりするコードを移植する際には、単にmain関数から呼び出される別名で同じ仮引数の関数を作ればいい。そもそも、main関数を再起呼び出ししたりアドレスを得たりするような実用的なコードは、あまり存在しないだろう。

C++にはCompatible type(互換型)が存在しない

Cには、互換型というものが存在する。例えば、タグ名以外はすべて同一の構造体などが該当する。C++は強い静的型付けを持っているので、そのような互換型は存在しない。

Cでは、そのような型非安全なコードは多いのではないかと思う。

明日も、宣伝のために標準型変換の変更点を解説する。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-11-27

CとC++の違い:字句編

京都C++勉強会の宣伝のために、CとC++の違いを、少しづつ解説することにした。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

C++はCの完全互換ではない。Cのあまり良くない部分は、変更して改良した。ここでは、そのような変更点のうち、互換性に特に問題のあるものを取り上げる。

今回は、字句編だ。

新しいキーワード

C++では、新しいキーワードが追加されている。C++で追加されたキーワードを名前に使っているようなCコードは、問題になる。

文字リテラルの型がintからcharに変更

Cでは、'a'の型は、intだった。これは、オーバーロード解決で問題になる。

// 実装依存の整数が出力される
std::cout << 'a' ;

C++では、文字リテラルの型をcharに変えた。

これにより壊れる可能性のあるコードとしては、sizeof('x')のようなコードが想定されている。しかし、そのようなコードはあまり多くないだろう。

文字列リテラルの型がconstになった。

Cでは、文字列リテラルの型はconstではなかった。C++ではconstだったが、C++03までは、文字列リテラルに限り暗黙にconstを消し去ることを認めていた。C++11では、そのような標準変換もなくなったので、以下のようなコードはエラーとなる。

// エラー
char * ptr = "hello" ;

このようなコードは、そもそも適切ではない。文字列リテラルの指し示すストレージを書き換えた結果は未定義だからだ。案外まだ、このような不適切なコードは残っているのではないだろうか。

明日も、宣伝のためにBasic Conceptsの変更点を解説する。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-11-26

ラップトップ用のインナーケースを買った

新しい15.6インチのラップトップを譲り受けたことはすでに述べた。このラップトップのパフォーマンスは申し分ないが、少々大きい。大きいのはいいのだが、最近はラップトップを持ち運んで、家の外で作業をすることが多い。その持ち運びがやや不便だ。

私は、昔使っていた13か14インチのラップトップ用のカバンを持っている。このカバンは、ラップトップを固定するためのポケットが付いているのみならず、背負うこともできれば手持ちのとっても縦横二箇所についているし、肩から下げる取り外し可能なヒモも付いているという、結構多機能なカバンなのだ。ただし、だいぶ傷んできて、背負いヒモの縫い目も危なげにみえるし、15.6インチのラップトップがポケットに入らない。ポケットに入れずに直接入れると、他にいくらも入らないし、他にもACアダプターやマウスやキーボードなどが直接あたって危なげだ。

私は、安いが高機能なリュックを持っている。腰で固定するヒモがあるし、外側から引っ張って中身を固定するためのヒモも四カ所についているリュックだ。このリュックは悪くないが、ラップトップを固定するためのポケットがついていない。このリュックに、他の荷物とともにラップトップを入れるのは怖い。

しかし、毎日ラップトップを持ち運ぶという事情もあるので、やはりなにか一つ、ラップトップ用のカバンを買わなければならないだろう。背負いヒモもついているものがよい。

大型の家電量販店に行って、色々とみてみたが、どうもいいものがない。カバンには背負いヒモがついていない。ラップトップ用のポケットがあるリュックもたくさん売っているのだが、どれもリュックとしては甚だ貧弱なのだ。しかも、値段も1,2万円する。質が低すぎて、値段に見合っていない。一体これはどういうことだろう。

色々と考えた結果、ラップトップ用のインナーケースを買うことにした。インナーケースはどんなに高いものでもせいぜい数千円なので、たとえ失敗しても数万円のカバンやリュックよりはましだ。インナーケースならば、カバンやリュックは別に高品質なものを使えばよい。

どのくらい頼れるのかはわからないが、撥水加工された表面で、適度に硬くて四隅も丈夫で、面はクッションになっているものを買った。

コンパイル時zip関数の書き方、並びに京都C++勉強会の案内

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

さて、昨日は、コンパイル時zip関数を書いた。ただし、コードだけで解説が欠けていた。今日は、解説をしようと思う。

zip

本の虫: 久しぶりにメタプログラミングらしいメタプログラミングをした

以下のような関数

template<std::size_t N, typename... T>
auto zip(const std::array<T, N>&... containers)
    -> std::array < std::tuple < T ... > , N >

が、以下のように動く。

std::array<int, 5> a = {1, 2, 3, 4, 5}; std::array<char, 5> b = {'a', 'b', 'c', 'd', 'e'}; zip<5>(a, b); // -> std::array<std::tuple<int, char>, 5> : (1, 'a'); (2, 'b'); ...; (5, 'e') std::array<int, 4> c = {1, 2, 3, 4}; zip<4>(a, c) // -> compile time error std::vector<int> d = {1, 2, 3, 4, 5} zip<5>(a, d) // -> complie time error

これ自体は、実行時関数ならば、以下のように書ける。

template < std::size_t N, typename ... Types >
auto zip_runtime( std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    std::array< std::tuple< Types... >, N > result ;

    for ( std::size_t i = 0 ; i != N ; ++i )
    {
        result[i] = std::make_tuple( containers[i] ... ) ;
    }

    return result ;
}

と、このように簡単なコードなのだが、これはconstexpr関数にできない。無駄なループがある。このようなコードは、リスト初期化を使えば、以下のように書ける。

std::array< std::tuple< Types... >, N >{
    { std::make_tuple( containers_0[0], containers_1[0]) },
    { std::make_tuple( containers_0[1], containers_1[1]) },
// ...
} ;

こういう形に落としこんでしまえば、最初から初期化としてarrayを構築できるし、constexpr関数にできる。

containersは、パック展開でいくらでも展開できるが、添字をどうにかしたい。これにはInteger Sequenceと呼ばれているテクニックを用いることができる。原理はN3493で解説されていて、C++14の標準ライブラリに入るのだが、残念ながら、C++11で実装しなければならないので、これを実装しなければならない。この論文と実装例は、すでに簡易レビューで紹介している。

本の虫: C++ 2013-01 mailingの簡易レビュー

template< std::size_t ... >
struct index_seq { } ;

template < std::size_t N, typename T >
struct make_index_seq_impl ;

template < std::size_t N, std::size_t ... I  >
struct make_index_seq_impl< N, index_seq< I ... > >
{
    using type = typename make_index_seq_impl< N-1, index_seq< N-1, I... > >::type ;
} ;

template < std::size_t ... I  > 
struct make_index_seq_impl< 0, index_seq< I ... > >
{
    using type = index_seq< I... > ;
} ;

template< std::size_t N >
using make_index_seq = typename make_index_seq_impl< N , index_seq< > >::type ;

これは、単にNを指定すると、0,1,2,3... Nまで整数型の非型テンプレートパラメーターパックを生成するための、簡単なメタ関数だ。この実装は簡易的なもので、テンプレートの再帰深度が線形に増えていくが、今回は特に問題としない。

ここまではいい。ではさっそく、これを使ってリスト初期化に展開されるコードを書こう。

template < std::size_t N, std::size_t ... I, typename ... Types >
constexpr auto zip_aux( index_seq< I ... >, std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    return std::array< std::tuple< Types ... >, N >{ { 
        // エラー
        std::make_tuple<I>( containers[I]... )...
    } } ;
} 

template < std::size_t N, typename ... Types >
constexpr auto zip( std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    return zip_aux( make_index_seq< N >(), containers ... ) ;
}

残念ながら、これエラーになる、なぜなら、パラメーターパックが2つもあって、その数も同じではないからだ。そのため、パック展開に失敗する

C++ Templates Metaprogrammingに書いてあるように、問題があるときは、もう一段階の参照を挟んでやるとよい。ここでは、パック展開されたコンテナーをパラメーターパクで、添字を非パラメーターパックで受け取ってtupleを返す関数を追加する。

template < std::size_t I, std::size_t N, typename ... Types >
constexpr auto make_unpacked_tuple( std::array< Types, N > const & ... containers )
    -> std::tuple< Types ... >
{
    return std::make_tuple( containers[I]... ) ;
}

このもう一段階の参照を使えば、以下のように書ける。

template < std::size_t N, std::size_t ... I, typename ... Types >
constexpr auto zip_aux( index_seq< I ... >, std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    return std::array< std::tuple< Types ... >, N >{ { make_unpacked_tuple<I>( containers... )... } } ;
} 

template < std::size_t N, typename ... Types >
constexpr auto zip( std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    return zip_aux( make_index_seq< N >(), containers ... ) ;
}

このように書けば、constexpr関数にできるzip関数の出来上がりだ。わざわざループで代入しなくても、構築時のリスト初期化で済ますことができる。

さて、冒頭でも書いたように、江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能や、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

2013-11-25

久しぶりにメタプログラミングらしいメタプログラミングをした

zip

これをみて、早速実装を始めたが、残念ながらボレロ村上さんに抜かれてしまった。

ボレロ村上の実装

ボレロ村上さんのコードを参考にしたわけではないが、書き終わってから見ると、同じになっていた。

江添の実装

#include <iostream>
#include <array>
#include <tuple>
#include <cstddef>


template< std::size_t ... >
struct index_seq { } ;

template < std::size_t N, typename T >
struct make_index_seq_impl ;

template < std::size_t N, std::size_t ... I  >
struct make_index_seq_impl< N, index_seq< I ... > >
{
    using type = typename make_index_seq_impl< N-1, index_seq< N-1, I... > >::type ;
} ;


template < std::size_t ... I  > 
struct make_index_seq_impl< 0, index_seq< I ... > >
{
    using type = index_seq< I... > ;
} ;

template< std::size_t N >
using make_index_seq = typename make_index_seq_impl< N , index_seq< > >::type ;

template < std::size_t I, std::size_t N, typename ... Types >
constexpr auto make_unpacked_tuple( std::array< Types, N > const & ... containers )
    -> std::tuple< Types ... >
{
    return std::make_tuple( containers[I]... ) ;
}

template < std::size_t N, std::size_t ... I, typename ... Types >
constexpr auto zip_aux( index_seq< I ... >, std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    return std::array< std::tuple< Types ... >, N >{ { make_unpacked_tuple<I>( containers... )... } } ;
} 

template < std::size_t N, typename ... Types >
constexpr auto zip( std::array< Types, N > const & ... containers )
    -> std::array< std::tuple< Types... >, N >
{
    return zip_aux( make_index_seq< N >(), containers ... ) ;
}

int main()
{
    constexpr std::array<int, 5>  a = { { 1, 2, 3, 4, 5 } };
    constexpr std::array<char, 5> b = { { 'a', 'b', 'c', 'd', 'e' } };

    auto c = zip<5>(a, b) ;


    for ( auto const & i : c )
    {
        std::cout << std::get<0>(i) << " , " << std::get<1>(i) << '\n' ;
    }
}

なお、ここで使っているindex_seqは、今、標準ライブラリに提案されている。

本の虫: C++ 2013-01 mailingの簡易レビュー

ちなみに、これはコンパイル時実行にこだわっているからこうなるのであって、実行時実行なら、普通に以下のように書ける。

zip.cpp

Ubuntu 14.04でもMir/XMirの採用はなし

[Phoronix] Ubuntu 14.04 LTS Won't Be Powered By Mir

[Phoronix] Canonical Commits To Mir For Ubuntu 14.10

まだMir/XMirは十分な完成度ではないとして、LTSリリースとなるUbuntu 14.04では、デフォルトで採用とはならないようだ。

吉田物語

願わくはこれを語りて非寮生を戦慄せしめよ

今日は昼前に吉田寮にやってきて、探索を行った。目的は、この場所の現状の記録と、話の収集である。

吉田寮は外から見ると、まるで廃墟同然だが、中からみても、やはり廃墟同然だ。ただし、そこには紛れもなく人間が生息している。

庭には、様々な動物が、食用として飼われている。私が確認した限りでは、ニワトリとヤギとウサギとエミューがいる。ネコもいるのだが、これはさすがに食用ではないだろう。

ここでは、あらゆるものが乱雑に放置されている。盗まれることもあるらしいが、果たしてどれが私物で、どれが捨てられているのか、そのへんは明確ではない。

ここでは、食べ物には所有の概念がないらしく、食べ物を放置していると、しょっちゅう食べられる。私の取材し得たO氏からは、炊飯器にご飯を炊いておき、いざ食べようとフタを開けたら、すでに誰かに食べられて空っぽだった事例を収集した。

ただし、ここで私が収集し、これから私が物語る話を読めば、むしろ食べてくれたほうがいくらかありがたいことを知るであろう。

決して開けてはならぬ封印されし炊飯器のこと

まだ遠からぬ昔、吉田寮入り口付近に、炊飯器が放置されていたそうだ。いつから放置されていたのか、正確に知るものはいない。数カ月かもしれないし、数年かもしれない。とにかく、長い間放置されてきたことに疑いはない炊飯器だ。問題なのは、その炊飯器には、どうやら中身が入っているらしいというのが、住人の間の暗黙の了解であった。

かくして、その炊飯器は、決して開けてはならぬ禁断の炊飯器として、長らく封印されてきた。まるで、魔封波を受けたナメック星人が封じられているとでも言わんばかりに、避けられてきた。

しかし、いつまでもかの封印されたる炊飯器を入り口に置いておくわけにはいかぬ。いずれは開けねばならぬこととて、とうとう、開封の儀を執り行う次第に決まった。

皆が万全の体制(無論、逃走の用意である)で見守るなか、決して開けてはならぬ炊飯器が開かれた。彼らは一体、何を見たのであろうか。

残念ながら、私がこの話を収集した某氏は、この続きをはぐらかして語ろうとしない。単に固まったご飯が入っていたという者もあり、黒いものが入っていたという者もあり、液状の何かが入っていたという者もあり、虫がたくさん湧いていたという者もあり、その詳細は判然としない。

2013-11-24

純粋仮想関数は定義を持てる

GitHubで公開しているC++参考書に、以下のようなpull requestが送られてきた。

Pure virtual function by daisukekoba · Pull Request #153 · EzoeRyou/cpp-book

純粋virtual関数は、宣言を分ければ、定義も持てるそうだ。実際にまともなC++コンパイラーでコンパイルしてみると、たしかにその通りだ。

どうやら、私の規格の文面の解釈が間違っていたらしい。

C++の規格に曰く、

10.4 paragraph 2

A function declaration cannot provide both a pure-specifier and a definition.

ひとつの関数宣言はpure指定子と定義の両方を提供することができない。

これを読むと、以下のコードがエラーになることがわかる。

struct S
{
// エラー、pure-specifierと定義を両方持つ
    virtual void f() = 0 { }
} ;

しかし、私は「ひとつの」という部分を見落としていた。つまり、複数の関数宣言を使えば、両方とも持てるのだ。

struct S
{
// pure-specifier
    virtual void f() = 0 ;
} ;

// 定義
void S::f() { } 

規格の文面を正しく解釈すると、このコードは正しいはずで、実際に、既存のC++コンパイラーはこのコードを通す。

これをなぜかと考えると、abstract classでも、デストラクターは定義したいという利用例がある。

class Base
{
    int * ptr ;
public :
    Base() : ptr( new int(0) ) { }

// コピーとムーブの特別なメンバーの宣言など

    virtual ~Base() = 0 ;
} ;

Base::~Base()
{
    delete ptr ;
}

class Derived : public Base
{
    virtual ~Derived() { }
} ;

なるほど、もちろん、このように書きたい。すると、pure virtual functionかつ定義をもつというデストラクターは、至極当然のように思われる。デストラクターに許されているのだから、一貫性を保つために、普通の非staticメンバー関数でも、当然許されるべきだ。

しかし、このことについて色々と試していた結果、以下のようなコードが書き上がってしまった。

struct Base
{
    virtual void f() = 0 ;
    virtual ~Base() = 0 ;
} ;

void Base::f() { }

Base::~Base()
{
// Derivedはすでに破棄されている
// デストラクター呼び出しは警告、実行時abort、ともになし。

// GCC, Clang、ともにコンパイル時警告
// GCCでは問題なく実行可能
// Clangでは実行時に純粋仮想関数呼び出しエラーで意図的にabort
    f() ; // Base::fを呼ぶ
}

struct Derived : Base
{
    virtual void f() { }
    virtual ~Derived() { }
} ;

int main()
{
    Derived d ;
}

なんと、GCCとClangでは挙動が違っているではないか。しかも、GCCでは問題なく実行できるのに対し、Clangでは実行時エラーとしてabortするという、実行時にまで影響を呼ぼす差異だ。これはどちらかのコンパイラーが間違っているのではないか。しかし、どちらの挙動が正しいのか。

私の当初の間違った考えでは、デストラクターも純粋仮想関数かつ定義をもつのに、警告も実行時abortもないため、どうも一貫性にかける。これは、コンパイラーがおかしいのではないか、とくに、Clangがおかしいのではないかと考えた。

久しぶりに、よくよく考えてもわからない問題だったので、私よりもっとできる人に聞いてみた。つまり、C++WGのMLにメールを投げた。すると、私の考えは全く持って見当違いだったことが明らかになった。

12.7で規定されているように、ポリモーフィックなオブジェクトの構築時、破棄時は、あたかもそのオブジェクトが最終的なオーバーライダーであるかのように振る舞う。Baseのデストラクター内で呼ばれている未修飾名fが、Base::fを呼ぶのはそのためだ。しかし問題は、未修飾名で呼び出すので仮想関数呼び出しになるということだ。仮想関数呼び出しで純粋仮想関数が呼び出された場合、挙動は未定義である。たとえ定義があろうとも、Base::fは純粋仮想関数であることに変わりはない。純粋仮想関数である以上、仮想関数呼び出しで呼び出された場合、挙動は未定義となる。未定義である以上、何が起きても文句は言えない。

そのため、この場合にBase::fを呼び出したい場合は、修飾名で呼び出して、仮想関数呼び出しを避けなければならない。

Base::~Base()
{
    Base::f() ; // OK
}

しかし、デストラクターはどうなのだ。なぜデストラクターにはコンパイル時警告も実行時エラーもないのだ。それはなぜかというと、デストラクター呼び出しは、たとえ仮想関数であっても、派生クラスから明示的に基本クラスのデストラクターが呼び出されたかのように振る舞うのだ。だから、仮想関数呼び出しではない。仮想関数呼び出しではない以上、問題はない。

したがって、GCCとClangの挙動は、どちらとも正しい。規格上未定義なのだから、何が起きても文句は言えない。ただし、GCCはコンパイル時に警告を出しているので、かろうじて問題がわかる程度だが、Clangは実行時にabortを出しているので、とても親切である。だからといって、GCCが規格違反の実装というわけではない。

ああ、まだまだ未熟だ。

2013-11-23

伝説のゲームプログラマー、John Carmack様がid Softwareから離脱

id Software founder John Carmack resigns | Polygon

Id Software founder John Carmack resigns | Hacker News

ビデオゲームに3D FPSというジャンルを作り上げた伝説のゲームプログラマー、John Carmack様が、id Sfotwareをお離れになられるそうだ。

Daikatanaとかいうクソゲーを作ったRomero様に続いて、Carmack様もidから去り、一つの時代が終わったのを感じる。

もはや、まともなFPSゲームは二度と作られないだろう。リアルタイムレンダリングの3DCGによるゲーム、特にFPSゲームはあまりにも大衆化してしまった。これからのシューターは、無線による遅延を気にしないほどの大味な作りになり、三人称視点になり、カバーやQTEだらけで、しかも何もしなくてもNPCが勝手に進めてくれる、そんな屁みたいなゲームに成り下がるだろう。

John Carmack様の離脱は寂しいが、もはやリアルタイム3DCG描画には、彼のような天才は必要ないのだ。3Dゲームエンジンなども、もはや一人の天才の手によって書かれるものではなくなっている。残念だが、それほど大衆化してしまったのだ。

聞けば、John Carmack様は最近、ゲームよりも、ヘッドギアなどの大掛かりな装置を使った拡張現実に興味を示されているご様子で、そのような研究開発している会社、Oculus VRでフルタイムで働くために、idを離れるのだそうだ。

拡張現実は、いまだに一般大衆が使えるほど安価な装置やソフトウェアがない。拡張現実がまともに一般人が楽しめるレベルにまで進化するのかどうかは、浅学近眼の筆者にはわからないが、Carmack様のあふれる才能を発揮して挑戦する場としては、ふさわしいのではないかと思う。才能あるものは、常に未知の分野を開墾するべきなのだ。すでに耕されて、安定した石高の田畑にとどまり、あたら才能を埋もれさせるのはあまりにももったいない。

2013-11-22

プログラミングを学ぶ環境について

昨日、今日と吉田寮にいて、数人集まって、それぞれ自分勝手にコードを書いていたわけだが、思うに、このような環境はプログラミングの学習環境としてかなりいいのではないかと思う。

結局、プログラミングというのは、講師が前の黒板に90分間板書したものを読んで学べるものではないのだ。自分で調べて、コードを書いて、動かして学ばなければならないのだ。

ただし、「自分で調べて」というのが、大抵の場合、非効率的になる。例えば、テンプレートメタプログラミングに詳しくないものが、CRTPのようなテクニックを必要とする場面に出くわしたり、ある型がPODであるかどうかを調べる方法(std::is_pod)について、自力で調べるとすると、無駄に時間がかかる。まずどこを調べればいいのかわからない。ドキュメントがどこにあるのかもわからない。

しかし、CRTPやstd::is_podのようなものは、理解しているものが教えれば、5分、10分で原理を教えられるようなものだし、ドキュメントがどこにあるのか指し示すのも一瞬ですむ。こういう時、複数人が、めいめい自分勝手に作業をしていて、たまに相談できるような環境があればいい。

ただ、そのような学習環境は、お互いのためにはなるが、金にはならないという問題がある。難しいものだ。

また、小規模なら、吉田寮でも勉強会を開けそうだが・・・あまりに汚らしい場所なので人を選ぶ。

江添とボレロ村上の京都C++勉強会、開催の告知と参加者募集のお知らせ

参加申し込み:江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

江添とボレロ村上の京都C++勉強会

江添とボレロ村上の京都C++勉強会

概要

12月16日に、京都にある、はてな京都本社で、C++の勉強会を開催します。参加申し込みは上下のATNDリンク先から行えます。

基礎情報

内容C++の勉強会
開催日2013年12月16日
時間19:00~22:00
場所〒604-0835 京都府 京都市中京区高宮町206 御池ビル8F (1階にセブンイレブンが入っているビルです)
会場名 セミナールーム(エレベーターを8階で下りてまっすぐ廊下を進んだ先が入り口です)
発表者江添亮ボレロ村上
参加枠40人
参加費無料

入場方法

御池ビル8階には、西側の玄関から入り、廊下をまっすぐ進むと見えるエレベーター1つで上がれます。

開場の時間帯(19:00~19:30)には、正面玄関はシャッターが閉まっている可能性が高いので、ご注意下さい。

また、西側の入口も19:40には施錠されるため、それ以降に入場される場合は、ドアの右側に備え付けのインターホンで「801」を押して呼び出して下さい。

セミナールームへは、エレベーターを8階で下りて、まっすぐ廊下を進んだ先にあるドアから入れます。

時間割

時間 内容 発表者
19:00-19:30 開場
19:30-20:20 C++14の新機能 江添亮
20:20-20:30 質疑応答 江添亮
20:30-20:40 休憩
20:40-21:30 すごいconstexprたのしくレイトレ! ボレロ村上
21:30-21:40 質疑応答 ボレロ村上

発表内容

タイトル:C++14の新機能

発表者:江添亮

内容:C++14のコア言語の新機能をすべて解説

スライド資料

タイトル:すごいconstexprたのしくレイトレ!

発表者:ボレロ村上

内容:constexprでのレイトレーシングの実装を通じて、ライブラリ設計や数学演算実装などの実践的テクニックから言語トリビアまでをたのしく学ぼうという主旨

その他

当日、Ustreamによる配信があります。

http://ustream.tv/channel/hatenatech

質問があれば、boostcpp@gmail.comまで

参加申し込み:江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

追記:申し込みキャンセルできるように設定

追記2:もし、今回の開催が平日の夜のために参加できないが、ぜひとも参加したい人が十分にいれば、来年にもどこかで開くかもしれない。

吉田寮に泊まることになった

ふとした縁で、京大の吉田寮に呼ばれた。吉田寮というのは、名前だけはしっていたが、まさか実際に行くことになるとは思わなかった。そしてこの記事は、吉田寮の中で書いている。

吉田寮に行くにあたって、事前に画像を検索すると、出るわ出るわ、何十年も前からタイムスリップしてきたような画像が出てくる。まさか、今もこの佇まいを残しているのだろうか。

今回呼ばれたのは、ある京大生が、C++勉強会の部屋として、京大の教室を借りられると連絡してきたことがきっかけだ。勉強会の詳細は、明日ATNDで公開するが、今回は、はてなのセミナールームで行うことになった。だが、京大の教室というのはかなりの人数が入るので、来年に勉強会を開く際には、使えるだろう。

それはさておき、今は吉田寮だ。吉田寮は、実際、画像の通りの佇まいを残していた。今にも倒れそうなほどボロボロだ。壁は穴だらけ、落書きだらけ、廊下にも部屋に物があふれ、おまけにドアには鍵がかかってない。

今日は一日、C++やプログラミング言語について語り合った。C++にはあまり詳しくない人も多いのに、C++14やC++17で提案されている新機能が、口頭で言うだけで通じるというのは、なかなか興味深い。

吉田寮は汚いが、私はとても気に入った。とても気に入ったので、200円払って一泊することにした。しかしこの、勝手に泊まってもあまり誰も問題にしなさそうな雰囲気はどうだろう。折田先生の精神は未だに残っているのだろうか。

吉田寮で興味深いのは、京大に関係ない人間もいるということだ。ニートとかフリーターとか、吉田寮が楽しくてわざわざ大阪から京大の近所に引っ越してきた人がいる。混沌とし過ぎていて現実感がない。

もっと解せないのは、女もいるということだ。一体、こんな汚い男だらけの環境に、どうやって女が生活していけるのか疑問だが、まあ、意外と犯罪は少ないそうだし、環境さえ気に入れば、いいところなのだろう。

最高に解せないのは、時期によっては子供までいるのだそうだ。まあ、暇人は常にいるし、子供には面白い遊び場だろう。

とても面白い場所だ。これを機会にちょくちょく遊びに来よう。

2013-11-20

引っ越し最終日

今日は引っ越しの最終日だ。部屋は不要品ごと売り渡すことになっているので、今日は最終の確認をしなければならない。もう、必要なものは全て運びだしたはずだが、念の為だ。

とりあえず、今日までは引っ越しで忙しいが、明日以降はだいぶ落ち着けるはずだ。

もったいなくも捨てなければならないこともある。例えば、高校の時の数学の教科書は、何かの役に立つかと思って今まで持っていたが、結局一度も開くことはなかった。必要ならば、後でいくらでも手に入るし、名残惜しいが、この際処分してしまうことにしよう。

新しい環境は意外と快適だ。まず場所が賑やかなので、歩いていける範囲で何でも揃う。

さしあたっては、ネット環境をどうするかということだ。今、100kbpsの回線が常時あるし、より帯域が必要ならば、無料や少額で利用できるWiFiがあるので、特に問題はない。落ち着いたら、WiMAXの契約を考えてみようと思う。C++の参考書が、数十人に売れたので、とりあえずWiMAXをしばらく契約することはできる。

もし、C++を詳細に解説した参考書が見つからなくて困っている者がいれば、私の自由なC++参考書が役に立つだろう。

Gumroadで購入:C++11参考書:C++11の文法と機能

本の虫: C++参考書の販売:C++11の文法と機能

GitHub: EzoeRyou/cpp-book

GitHubからzipでダウンロード

GitHub Pagesでの閲覧:C++11の文法と機能

本の虫: C++11参考書の公開:C++11の文法と機能

2013-11-19

(仮)京都で行うC++勉強会について現時点で決まっていること

かねてから計画と準備をしていた、京都で行うC++勉強会の正式な告知と募集は、今週末に行う予定だが、現時点で決まっていることを公開しておく。

場所は、はてなの好意で、はてな京都本社のセミナールームを使わせてもらえることになった。

まさか江添がC++だけで伝わるとは、思えばC++の規格に絞って深く学び始めてから、もう10年はたつ。

今回は、場所が確保できたので、参加料の徴収は考えていない。

日時は、2013年12月16日、時間は19:00頃から受付して、19:30から発表、22:00までには終了を予定している。終了時間はまだ確定していない。

発表者は、私とボレロ村上さん。私の発表は、C++14のコア言語の新機能すべて、ボレロ村上さんはまだ詳細が決まっていないが、constexprについて発表するそうだ。constexprの解説か、あるいはコンパイル時レイトレーシングか。

時間の都合上、発表は、大きな発表2つに絞ることにした。

勉強会には、終わった後の懇親会もつきものだが、今回は終了時間が遅いので、特にあらかじめ表立って計画することは考えていない。終わった後に、夜遅くだが一緒に食事でも行きたい人がいるかどうか。

実は、京大の教室が借りられるかもしれないという話もあったが、今回は、はてなのセミナールームで行うことにした。京大の教室は広いので、もし借りられて、人数が集まるならば魅力的だ。来年に検討してみたい。

2013-11-18

ひざ上時代の到来

というわけで、しばらくはこの貰い物のラップトップで作業する。ひざ上時代の到来だ。

ラップトップとはいえ、パフォーマンス的には文句のつけようがない。

さようならデスクトップ、こんにちはラップトップ

6年間もの長きに渡り、直しつつ使っていたこの思い出深いデスクトップともお別れだ。思えばいろいろあった。CPUファンと電源は壊れたので交換したし、GPUは3枚も交換しているし、HDDもOSを変える際に変えた。

ただ、IntelのQ6600や、DDR2の4GBのメモリは、さすがに時代に遅れてきた。

幸い、この思い出深いデスクトップを破棄することだけは免れたが、次に使う日は、いつになるのか分からない。新しく引っ越す場所は、仮の家で、数ヶ月でまた引っ越す予定だからだ。使えたとしても、そろそろ時代に合わなくなってきている。

残念ながら、私が高校生の一夏バイトをして買った、始めて私が所有したコンピューターは、HDD以外は破棄することになる。もう6年使っていないし、そのHDDもIDEだし、そもそも動くかどうかもわからないが、HDDだけは何が入っているかわからない。6年前とはいえ、ログインcookieも残っているし、個人情報のかたまりである。たしかパスワードも平文で保存していたような気もする。捨てるにしても破壊して捨てなければならない。

とはいえ、今は時期が悪い。いや、ことコンピューターを購入するにあたっては、いつだって時期が悪いのだが、特に今は時期が悪い。そろそろDDR4が市場に出回る頃で、できればそれを待ってから買いたいものだ。また、その時までに、経済上の問題を解決しなければならない。

これから代わりに使うのは、このAcerのラップトップ。だいぶ増設されていて、もてあますぐらいのパフォーマンスになっている。6年前から使っている思い出深いデスクトップよりパフォーマンスが高い。

インターネットは、とりあえず100bpsのDTIの格安SIMのカードによるLTEがあるが、これは来年の半ば辺りまでの借り物だし、C++の参考書の売上で、数年ぐらいは無線インターネット接続を契約できるぐらいにはなったし、引っ越しが落ち着いたら、無線によるインターネット接続の契約を考えなければならない。

最近は喫茶店や行政によるWiFiも発達してきたので、早いインターネット回線が欲しい場合も、さしあたって苦労はしないが、やはり常時使えて、数Mbpsの帯域のあるインターネット接続がほしい。

今考えているのは、WiMAXだ。WiMAX2+も、値段としては変わらないのだが、残念ながら端末がクソすぎて使い物にならない。無駄にでかい上に、タッチパネルやらファイルサーバーやら無駄な機能がゴテゴテとついていて、そのためにバッテリー駆動時間も短いし、それでいて肝心の無線通信の感度が最悪と来ている。2年縛りも難点だ。そのため、旧来のWiMAXを考えている。

WiMAX端末は、クレードル付きのURoad-Aeroがいいのではないかと思う。クレードルを装着すれば有線LANも使えるそうだし、わざわざ無線を二重に使うことに違和感を覚える私としては、精神的にも楽だ。

さて、電源を落とすか。このデスクトップを動かせば、引越し作業はほぼ終わりだ。あとはラップトップの仕事だ。