range-based forとstd名前空間
Boost.Coroutineに関してBoost users MLでrange-based forに関する面白い話が流れたので紹介したい。
この話は私も初めて聞いて驚いた。
C++11で新規追加されたrange-based forはconceptが削除されたタイミングでその挙動をどうするかで議論していた。なつかしい。
本の虫: range-based forに対する意見求む
- 配列を特別扱い
- class typeの場合、begin()/end()を呼べれば呼ぶ
- そうでなければstd名前空間をassociated namespacesに加えた上でADL
となりました。
しかし、ADLは挙動が非常にわかりづらく、特に問題なのがunqualified lookupするのかしないのかはADLの定義には書かれていません。
どちらかと言えば、unqualified lookupした結果、更にADLを加えるというのが本来意図された挙動でした。
さて、range-based forは最終的にADLするということになったわけですが、ここでunqualified lookupするかしないかという問題が出てきました。
結局この問題はDR1442*2となり、ADL時にはunqualified lookupをしないとなりました。
実際、GCCやClangといったコンパイラは、range-based for実装当初からunqualified lookupを行いません。
struct X { }; int main() { struct X x; int * begin(X &); int * end(X &); begin(x); // unqualified lookup for (auto _ : x) ; // エラー: begin/endが見つからない }
ところでこのDR1442ですが、よく見るとADLの挙動の明確化(unqualified lookupしないことの明確化)だけかと思うと、そうではありませんでした。
なんと、std名前空間をassociated namespaceに加えるという文言を削除しています。
つまり、これまでwell-formed*3だった以下のコードがill-formedとなるわけです。
namespace mylib { struct my_very_very_awesome_container { }; } namespace std { int * begin(mylib::my_very_very_awesome_container &) { return nullptr; } int * end(mylib::my_very_very_awesome_container &) { return nullptr; } } int main() { mylib::my_very_very_awesome_container c; for (auto x : c) (void)x; // std名前空間はassociated namespaceなのでbegin/endが呼ばれるはず }
なにせstd名前空間をlookup対象にするという文言を消しているので。
このassociated namespaceに関する挙動については、melpon氏謹製のwandboxによると
- clang 3.0 ~ 3.1
- gcc 4.6 ~ 4.8
の間は、よく知られた(と思う)std名前空間をlookupに含める挙動を示すようだ。
C++11として発行された規格ではstd名前空間を含めるはずだが、C++14ではなく、DRとして取り込まれたのでこれはもはやC++11の挙動だといって過言ではないだろう*4。
この挙動で頭を悩ませるのはboostのようなライブラリを書いている場合だろうから多分一般的には問題とはならないだろう。
Boost.Coroutineはstd名前空間にbegin/endを置いたので今回その対象となってしまった。
元議論:
Boost - Users - Cannot use Boost.Croutines with range based for
DR1442:
C++ Standard Core Language Defect Reports and Accepted Issues
*1:私はWGの人間ではないので積極的に議論されたかは知らない
*2:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442
*3:これがwell-definedだと言い切る自信がない。言い切る自信がある方、ぜひコメント頂きたい
*4:保証はしない
Debian GNU/Hurd 2013のインストールでパーティションを切りたい
Debianのインストールから、カーネルビルドまで...はいかない - にゃははー のハマリポイント4をなんとか回避できた。
結論から言うとprocfsがmountsを提供しないのが原因で、手動で切ったパーティションがマウントされているかを確認できていなかったのが原因でした。
具体的にはDebian GNU/Hurd 2013のインストールメディアは僅差でGNU Mach 1.3.99/Hurd 0.3という古いバージョンで収録されているが、手元のGNU Mach 1.4/Hurd 0.5では/proc/mountsがあったので、頑張って手動でこのファイルを作ればよかった。
手順としては、パーティション切ったところで何とかしてshellをとって
# settrans -g /proc # cat > /proc/mounts /dev/hd0s8 /target ext2fs defaults 0 0 /dev/hd0s3 /target/boot ext2fs defaults 0 0
ってする。
catめんどかったらnanoで。vimもviも無いです。
あとdpkgもないので、hurd 0.5を頑張って持ってきても手で頑張ってやらないといけないので普通にproc書いたほうが楽だと思う。
/proc/mounts 以外のprocfsなものはどうやら使わないみたいなので、/procにmountsしかなくても良かったです。
expert modeでしか確認してないので他のインストール方法でどうやってshell取るかは知らないです。多分出来ないです。
ほげ〜
Boost.Range でも regular が使いたい! - C++ AdC 2013
partake.in の12日目です。
もう一個のカレンダーの方で激おことかforkforkとか言ってたら、なんかみんな頑張ってるしカレンダー名に(fork)とか付いてしまってて申し訳ないなーとか思ってたり少しはしているのですが、特にカレンダー書く予定はないです。
ネタを Modularized Boost(GitHubへ移行したリポジトリ)を使用する - イグトランスの頭の中 に掻っ攫われてしまったので急遽頑張って考えました。
嘘です特に考えてませんでした。
ところがつい先日会社の同期が Boost.Range に足下掬われていて丁度いいかなと思ってネタにします。
続きを読むC++ Advent Clandar 2013 1日目 (forkした方)
※注: これはforkした方の。C++ (fork) Advent Calendar 2013 - Adventar
今年もAdvent Calendarの季節です。
しかも驚くべきことにC++ Advent Calendarはforkしました。あと先に断っておきますが、25日やらないです。
立ちあげた本人が表にもこちらにも書こうとしていないのは一体どういうことでしょうか。激おこです。
表のカレンダーは多分ガチなので、こっちはこれまでのC++関連のAdvent Calendarを振り返って見たいと思います。
私が参加したカレンダーしか知らないので、もしかしたら抜けがあると思いますが、ご容赦を。
今年参加するAdvent Calendar 2013
びぼうろく
C++ Advent Calendar 2013
担当日 :12/1(Sun)
書くこと:C++ACの傾向と対策
ついにC++ Advent Calendarもforkする時代です!!!
C++ Advent Calendar 2013 - PARTAKE
担当日 :12/12 (Thu)
書くこと:なにか
本当になにも考えていない。やばい。
ディストリビューション/パッケージマネージャー Advent Calendar 2013 - Qiita [キータ]
担当日 :12/18 (Wed)
書くこと:Debianのこと
いつもFedoraがメインで別にDebianスキーというわけでも無いけど、Debianしか選択肢が無いので仕方なくDebianで書く
Boost.Coroutine with 1.55.0 Beta 1 RC
もうBoost 1.55.0の時季となったわけで、リリースノートの翻訳作業も進めている。
Boost 1.55.0のリリースノート翻訳を更新 - Faith and Brave - C++で遊ぼう
今回はBoost.PredefというBoost.Configみたいな感じのものが来る。
どうせ誰かが解説するし、変更点とかは次のBoost.勉強会でアキラさんが発表するだろう。
ということで、私は割と見守ってきた(つもりでいる)Concurrentライブラリをつついていた。
過去にOliverはいろいろやってくれていたわけだけど、最近は何事もなかったように思えていたので気を抜いていた。
Boost.Contextの怒涛の変更 - にゃははー
Boost.Contextのnamespace - にゃははー
1.55.0のリリースノートを覗いてみると
New interface (unidirectional data transfer)
と書いてあるわけである。
フム、新しいインターフェイスかどんなものだろう。
当然www.boost.org上にドキュメントはまだ置かれないので、ソースを読む必要がある。
どうやらGeneratorを実装しましたということらしい。
邦訳版のリリースノートの方にも簡単なコード例を載せたが、一応こちらにも示す。
boost::coroutines::coroutine<int>::pull_type gen( [](boost::coroutines::coroutine<int>::push_type &yield) { for (int i : { 0, 1, 2, 3 }) yield(i); }); for (int i : gen) std::cout << i << std::endl;
まぁシンプルで良いのではないか。
さて、ここまで気を抜いていた私は、そのままなんとなく昔からあるドキュメントについても眺めてみた。
coroutine.qbk
[section:coroutine Coroutine]
__boost_coroutine__ provides two interfaces - one with uni- and one with bidirectional
data transfer (deprecated).
[section:old Bidirectional coroutine (['deprecated])]
[note This interface is deprecated but can be used by compiling the code with
compiler flag BOOST_COROUTINES_OLD.]
何を言っているかわからないだろうが、これまでのインターフェイスは非推奨となった。
BOOST_COROUTINES_OLDマクロが必要らしい。
ここでやっと私はコードを実際にコンパイルしてみようと考えた。
しかし、uniなインターフェイスでどうもコンパイルが通らない。
なんかincomplete typeがなんちゃらと言われる。
coroutine.hppを眺める。
coroutine.hpp
#ifdef BOOST_COROUTINES_UNIDIRECT #include <boost/coroutine/v2/coroutine.hpp> #else #include <boost/coroutine/v1/coroutine.hpp> #endif
え、BOOST_COROUTINES_OLDどこいった...
とりあえずBOOST_COROUTINES_UNIDIRECTつけたらコンパイル通ったし、期待通り動いたが、どうも釈然としない。
ので、あとでメール投げます。