2014-12-29

近況

私の住んでいる妖怪ハウスに海外から不思議な荷物が贈られてきた。宛名はRYOU EZOEになっている。

開けてみると、DON'T TRACK USと書かれたTシャツが入っていた。

おそらくは、Don't Track Us T-Shirt – Duck Duck Goではないかと思われる。

29日は秋パンに今年最後のボルダリングに行く。

30日は、青春18切符で京都まで移動する予定だ。

どうも最近、C++以外のブログ記事がおろそかになってしまっているようだ。なにか書こうと思ったが、夜も遅いのでもう寝なければならず、長文が書けない。

2014-12-24

C++14の新機能の解説を戻り値の型推定まで書いた

年末だというのに忙しくC++14の新機能の参考書を書いている。とりあえず関数の戻り値の型推定まで書いた。

巻末: C++14の新機能

C++11: Syntax and Feature

もちろんクールなキッズが皆使うというGitHubで管理している。

EzoeRyou/cpp14-appendix

EzoeRyou/cpp-book

ところで、興味深いニュースがあるようだ。

ドワンゴ、IT技術書出版新ブランド「アスキードワンゴ」を設立 - 週アスPLUS

IT技術書出版ブランド「アスキードワンゴ (ASCII DWANGO)」立ち上げのお知らせ|ニュース|広報情報|株式会社ドワンゴ

2. C++11/14の参考書(仮題)

ドワンゴ所属のエンジニアによるC++11/14の文法と機能についての解説書です。

ドワンゴ所属のエンジニア、はて。C++11/14の解説書、はて。

紙に印刷された本の需要はどのくらいあるのだろうか。

ドワンゴ広告

この記事はドワンゴ勤務中に執筆した。

今日も有給取得者が多い様子。今夜もドワンゴのボルダリング部の恒例のボルダリングに行く予定。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-22

C++14の新機能の解説

C++11のコア言語の参考書をすでに書いたが、時代はすでにC++14になっている。C++14の新機能の参考書も書きたいが、既存の参考書を更新するのは骨が折れる。

そこで、C++14の新機能だけを解説する短い文書を巻末という形で書くことにした。まだ執筆途中だが、GitHubで公開しながら編集することにした。

EzoeRyou/cpp14-appendix

巻末: C++14の新機能

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日は社内に人が少ない。有給取得者が多そうだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-21

各言語のARVv7とx86-64での実装のパフォーマンス比較

LPATHBench/writeup.md at master · logicchains/LPATHBench

同じ箇所に二回訪れずに最も長い経路を見つけるコードで。各言語の実装を、ARMv7とx86-84においてベンチマークしてみた結果が公開されている。

記事に書いてあるように、これは、ARMv7とx86-64のプロセッサーのベンチマーク比較ではなく、各言語の実装が、ARMとx86-64でどれだけ効率的に実装されているのかを比較している。

たとえば、C++はARMにおいてはx86-64の74%のパフォーマンスを出している。しかし、ARM版OpenJDKはなんと29%の速度しか出ていない。OracleによるJava実装は、40%ぐらいのパフォーマンスを出している。

コードはとても短いが、パフォーマンス改善のためのpull requestがどんどんよせられたらしく、その結果が興味深い。Javaでクラスではなく配列を使うようにしたら速くなったとか、C#のイテレーターは結構オーバーヘッドがあるだとか。

luajitが恐ろしく速いのが興味深い。

2014-12-19

.git/configが書き換えられるgitの脆弱性

WindowsとMac OS X用の公式gitクライアントの脆弱性により、.git/configが書き換えられ、任意のコマンドが実行されてしまう問題が修正されたようだ。

ANNOUNCE Git v2.2.1 and updates to older maintenance tracks

何が問題なのかというと、WindowsやMac OS Xのファイルパスの取り扱いで、異なるが同一として扱われる文字があることだ。

たとえば、Windowsでは、".git~1/config"というファイルパスは、".git/config"というファイルパスと同等のものとして扱われる。Mac OS XのHFS+でも、U+200cのような文字が無視されるので、".g/u200cit/config"が、".git/config"と同等に扱われる。

この結果。そのような名前のレポジトリをcloneしたWindowsやMac OS X環境では、.git/configが上書きされ、任意のコマンドを実行可能になってしまう。

GNU/Linuxでcase-sensitiveなファイルシステムを使った環境では、この問題には影響されない。

修正内容として、WindowsとMac OS X環境では、そのような一部の特殊な文字を拒否するようになったということだ。また、GNULinuxのような環境やでも、クロスプラットフォーム対応のため、そのような文字を拒否するオプションが追加されたそうだ。

2014-12-18

12月25日、妖怪ハウスでケーキ会、12月27日にボドゲ会

特に何をする予定もないし、何も用意はしないが、年末は暇なので、妖怪ハウスで消極的に人を集めてみようと思う。

12月25日はクリスマスなので、妖怪ハウスにケーキでも用意しておこうと思う。

12月27日は、今年最後のボードゲーム会を開きたいものだ。

人が集まるかどうかはわからないが、告知だけしておく。

妖怪ハウスの住所は、中野区野方5-30-13 ヴィラアテネ401となる。


View Larger Map

2014-12-17

プレシジョンダイス

筆者は、ダイスの目にはさんざん悩まされてきた。多くのボードゲームではダイスを使う。問題は、そのダイスの目が明らかに偏っているのではないかということが度々起こるからだ。

例えばカタンだ。カタンでは、六面ダイスを二個使い、目の合計によって該当する土地の資源を得る。六面ダイスを二個振った目の合計値の確率は、2と12が最も少なく1/36、7が最も多く21/36となっている。ところが、今まで経験したカタンでは、よく出るはずの6,7,8がなかなか出なかったり、なかなか出ないはずの2や12が多く出たりすることがたびたびあった。

これは、ダイスの加工精度の問題である。ダイスの加工精度に問題があると、当然出目も偏ってくる。

プレシジョンダイスと呼ばれているものがある。表面に目の凹みがなく、よく研磨されている加工精度のいいダイスである。今、プレシジョンダイスを買うには、どうやらバックギャモン協会のWebサイトから購入するのが手っ取り早いようだ。

プレシジョンダイス - SHOP | 日本バックギャモン協会

そこで、実際に購入してみた。ついでにダイスを降る際も、ダイスカップとダイストレイを利用するようにしてみた。

先週から何度かカタンや街コロをしているが、ダイスの出目に違和感のある偏りは見られなかった。

これから六面ダイスを使うボードゲームの際には積極的に使っていきたい。

2014-12-16

C++14に入る機能テストマクロの一覧

現実のコンパイラーにおいて、C++11やC++14、そして今制定されようとしている各種TSやC++1zなどの機能は、個々に実装される。その場合、あるコンパイラーのあるバージョンは、rvalueリファレンスを実装している、その次のバージョンはconstexprを実装したという、中途半端に機能を実装した状態になる。

その結果、現実には、往々にして以下のようなコードが書かれることになる。

#ifndef __USE_RVALUE_REFERENCES
  #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \
      _MSC_VER >= 1600
    #if __EDG_VERSION__ > 0
      #define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410)
    #else
      #define __USE_RVALUE_REFERENCES 1
    #endif
  #elif __clang__
    #define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
  #else
    #define __USE_RVALUE_REFERENCES 0
  #endif
#endif

標準規格としては、一部機能だけ実装することを推奨するのではないが、現実がこうである以上、ある機能が実装されているかどうかを調べる標準のプリプロセッサーマクロが存在するべきである。

そこで提案されているのが、Feature-testing recommendations for C++だ。

この提案では、C++の主要機能が実装されている場合、特定の名前のプリプロセッサーマクロが事前に定義されることとなる。例えば、rvalueリファレンスの場合、__cpp_rvalue_referencesという名前のプリプロセッサーマクロが定義される。

マクロの名前は、名前の衝突を避けるため、プレフィクスが付けられる。コア言語機能ならば__cpp_、ライブラリー機能ならば__cpp_lib_である。機能名は、その機能の論文のタイトルから採用される。

マクロの値は、その機能がドラフトに採用された年と月を表現している。これにより、標準規格策定中にドラフトが更新された場合、値も更新される。たとえば、C++11の機能である__cpp_rvalue_referencesの場合、2006年の10月にドラフト入りしたので、その値は200610となる。

特定のヘッダーファイルがあるかどうかを調べるプリプロセッサーの機能、__has_includeが追加される。これは、#ifや#elifの中で使うことができる。

#ifdef __has_include
#  if __has_include(<optional>)
#    include <optional>
#    define have_optional 1
#  elif __has_include(<experimental/optional>)
#    include <experimental/optional>
#    define have_optional 1
#    define experimental_optional
#  else
#    define have_optional 0
#  endif
#endif

機能テスト推奨に対応している実装で、#ifdefで__has_includeを記述すると、定義済みだと評価される。#ifや#elifで__has_include(ヘッダー)と記述すると、そのヘッダーが存在する場合はtrueとなる。

同様に、特定のattributeがあるかどうかを調べるプリプロセッサーの機能、__has_cpp_attributeが追加される。

#ifdef __has_cpp_attribute
#  if __has_cpp_attribute(deprecated)
#    define ATTR_DEPRECATED(msg) [[deprecated(msg)]]
#  else
#    define ATTR_DEPRECATED(msg)
#  endif
#endif

具体的なマクロ名

実際に論文を読めばいいと思うのだが、とりあえずここにも書いておく。ほとんどの機能は、このブログやC++11の参考書で解説したはずだが、まだ知らない読者はいるのだろうか。なにか新たに解説して欲しい機能があればコメントで言えば解説するつもりだ。

C++98機能

機能 セクション番号 マクロ名 ヘッダー
実行時型情報 5.2 __cpp_rtti 199711 predefined
例外 15 __cpp_exceptions 199711 predefined

C++11機能

文書番号 文書名 セクション番号 マクロ名 ヘッダー
N2249 ユニコード文字型 2.13 __cpp_unicode_characters 200704 predefined
N2442 生文字列リテラルとUnicode文字列リテラル 2.13 __cpp_raw_strings 200710 predefined
__cpp_unicode_literals 200710 predefined
N2765 User-defined Literals 2.13, 13.5 __cpp_user_defined_literals 200809 predefined
N2927 lambda式 5.1 __cpp_lambdas 200907 predefined
N2235 constexpr 5.19, 7.1 __cpp_constexpr 200704 predefined
N2930 Range-Based for 6.5 __cpp_range_based_for 200907 predefined
N1720 static_assert 7 __cpp_static_assert 200410 predefined
N2343 Decltype 7.1 __cpp_decltype 200707 predefined
N2761 属性(attribute) 7.6 __cpp_attributes 200809 predefined
__has_cpp_attribute(noreturn) 200809 predefined
__has_cpp_attribute(carries_dependency) 200809 predefined
N2118 rvalueリファレンス 8.3 __cpp_rvalue_references 200610 predefined
N2242 可変長テンプレート(Variadic Templates) 8.3, 14 __cpp_variadic_templates 200704 predefined
N2672 初期化リスト(Initializer List) 8.5 __cpp_initializer_lists 200806 predefined
N1986 コンストラクターのデリゲート 12.6 __cpp_delegating_constructors 200604 predefined
N2756 非staticデータメンバーの初期化子 12.6 __cpp_nsdmi 200809 predefined
N2540 継承コンストラクター 12.9 __cpp_inheriting_constructors 200802 predefined
N2439 リファレンス修飾子(*thisへのムーブセマンティクス) 13.3 __cpp_ref_qualifiers 200710 predefined
N2258 テンプレートエイリアス 14.5 __cpp_alias_templates 200704 predefined

C++14機能

まだこのブログで詳細に解説していない機能もあるはずだ。

文書番号 文書名 セクション番号 マクロ名 ヘッダー
N3472 2進数リテラル 2.14 __cpp_binary_literals 201304 predefined
N3781 シングルクオートによる数値区切り 2.14 __cpp_digit_separators 201309 predefined
N3648 汎用lambdaキャプチャー 5.1 __cpp_init_captures 201304 predefined
N3649 ジェネリックlambda式 5.1 __cpp_generic_lambdas 201304 predefined
N3778 サイズ付き解放関数 5.3, 18.6 __cpp_sized_deallocation 201309 predefined
N3652 constexpr関数の制限緩和 5.19, 7.1 __cpp_constexpr 201304 predefined
N3638 関数の戻り値の型推定 7.1 __cpp_decltype_auto 201304 predefined
__cpp_return_type_deduction 201304 predefined
N3760 [[deprecated]]属性 7.6 __has_cpp_attribute(deprecated) 201309 predefined
N3653 アグリゲート初期化とメンバー初期化子の同時利用 8.5 __cpp_aggregate_nsdmi 201304 predefined
N3651 変数テンプレート 14, 14.7 __cpp_variable_templates 201304 predefined
N3658 コンパイル時整数シークエンス(index_sequence) 20 __cpp_lib_integer_sequence 201304 <utility>
N3668 exchange()関数 20 __cpp_lib_exchange_function 201304 <utility>
N3670 tupleで型を指定できるget 20.2-20.4 __cpp_lib_tuples_by_type 201304 <utility>
N3887 テンプレートエイリアスを使ったtuple_element_t 20.3-20.4 __cpp_lib_tuple_element_t 201402 <utility>
N3656 make_unique 20.7 __cpp_lib_make_unique 201304 <memory>
N3421 greater<>のテンプレート実引数の省略 20.8 __cpp_lib_transparent_operators 201210 <functional>
N3462 std::result_ofをSFINAEフレンドリーにする変更 20.9 __cpp_lib_result_of_sfinae 201210 <functional>
N3545 integral_constantにconstexprなoperator ()を追加する変更 20.9 __cpp_lib_integral_constant_callable 201304 <type_traits>
N3655 エイリアステンプレートでメタ関数をラップして::typeを_tにする変更 20.9 __cpp_lib_transformation_trait_aliases 201304 <type_traits>
LWG 2112 is_finalの追加 20.10 __cpp_lib_is_final 201402 <type_traits>
LWG 2247 std::nullptr_t可動化を調べるis_null_pointer 20.10 __cpp_lib_is_null_pointer 201309 <type_traits>
N3642 chronoとstringに対するユーザー定義リテラルの追加 20.11 __cpp_lib_chrono_udls 201304 <chrono>
21.7 __cpp_lib_string_udls 201304 <string>
N3657 連想コンテナでkey_typeに変換可能な型から検索する機能 23.4 __cpp_lib_generic_associative_lookup 201304 <map>
<set>
N3644 Null Forward Iterators 24.2 __cpp_lib_null_iterators 201304 <iterator>
LWG 2285 make_reverse_iterator 24.5 __cpp_lib_make_reverse_iterator 201402 <iterator>
N3671 equal, mismatch, is_permutationで二つのrangeをとるオーバーロード 25.2 __cpp_lib_robust_nonmodifying_seq_ops 201304 <algorithm>
N3779 std::complexのユーザー定義リテラル 26.4 __cpp_lib_complex_udls 201309 <complex>
N3654 quotedライブラリ 27.7 __cpp_lib_quoted_string_io 201304 <iomanip>
N3659 shared_mutex 30.4 __cpp_lib_shared_mutex
__has_include(<shared_mutex>)
1 predefined
N3891 shared_mutexをshared_timed_mutexに改名 30.4 __cpp_lib_shared_timed_mutex 201402 <shared_mutex>

疲れた。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

Google Newsに強制課金する法律、あっけなく失敗

Spanish Newspaper Publishers' Association Now Asks Government To Help Stop Google News Closure | The Spain Report

スペインでは、Webサイトが報道機関のWebサイトをわずかでも引用する場合、報道機関に対し対価を支払わなければならないという法律を、報道機関のロビー活動により成立した。それを受けて、Googleは、Google Newsはそれ自体が金を生み出してはいないので、スペイン版を廃止すると宣言した。

どうやら報道機関のロビー団体はスペイン政府にGoogle Newsを廃止しないように何か行動をせよと言っているらしい。不思議なことだ。

ちなみに、ドイツでも同等の法律ができている。そのときもGoogle Newsは廃止を宣言した。その結果、Webトラフィックが激減したため、報道各社は、Googleと特別に取引して、Googleは対価を支払わなくてもよいということになった。その結果、Googleの独占的地位をますます強固たるものにしてしまった。

この件に関してはGoogleの方が役者は上だということだろう。

それにしても、市場をほぼ独占している最大手のGoogleが自らやめると宣言してくれたのだから、今から報道各社で検索サービスを開発して公開すれば、市場シェアを取れるはずだが、それはしないらしい。もちろん、Googleほどの効率を出すのは難しいだろうし、実際にGoogleが主張する通り、検索サービス単体は直接利益にならないのだろうが。

2014-12-14

Microsoftがbitcoinによる支払いを受け付けるらしい

How do I use Bitcoin with my Microsoft account?

Microsoftが米国でbitcoinによる支払いを受け付けるらしい。

なんともまあ、面白い流れだ。

2014-12-12

C++1zに採択された新機能

C++1zともC++17とも呼ばれているC++の次の規格には、まだ大きな機能は採択されていない。それでも、いくつかドラフト入りしている新機能はあるので、ここではその機能を紹介していく。

いつも通り、ここに書かれている内容はまだドラフト段階の機能であり、今後変更されたり、取り除かれたりする可能性もある。

N3928: メッセージ無しstatic_assert

C++11で追加されたstatic_assertには、文法上、必ず文字列リテラルを記述しなければならなかった。

static_assert( expr, "Captain Obvious To the Rescue! expr is false.") ;

この文字列リテラルは、実装が診断メッセージ(例えばコンパイラーのエラーメッセージ)に使うことができる。しかし、C++14までは、文字列リテラルが文法上必須で、必ず記述しなければならなかった。

そこで、文字列リテラルを記述しなくても良い文法が追加された。

static_assert( expr ) ;

N4086: トライグラフの除去??!

トライグラフが文面から削除された。

N4051: テンプレートテンプレートパラメーターにtypenameキーワード

C++14まで、テンプレートテンプレートパラメーターの文法は、classキーワードしか使えなかった。

template < 
    template < typename T >
    class U // typenameキーワードは不可
> struct X ;

typenameも使えるようになる。

template < 
    template < typename T >
    typename U // typenameキーワードが使える
> struct X ;

N4295: Fold式

パラメーターパックの中身すべてに対して演算子を適用したい場合、再帰的なテンプレートを書く必要がある。例えば、引数をすべてoperator +で合計する関数テンプレートを書くと、以下のようになる。

template < typename T >
T sum( T && t )
{
    return t ;
} 

template < typename T, typename ... Types >
T sum( T && t, Types && ... args )
{
    return t + sum( std::forward<Types>( args ) ... ) ;
}

いかにも面倒だ。やりたいことは、a1 + a2 + a3 + ... + aNということなのに、この記述はあまりにも冗長すぎる。

そこで提案されているのが、fold式だ。パラメーターパックpにたいして、(p + ...)と書くと、p1 + p2 + p3 + ... pNとパック展開してくれる。

fold式を使うと、以下のように書ける。

template < typename ... Types  >
auto sum( Types && ... args )
{
    return (args + ...) ;
}

fold式では、括弧は必須である。

template < typename ... Types  >
auto sum( Types && ... args )
{
    // エラー
    return args + ... ;
}

fold式には、left foldとright foldが存在する。

(... op e)は、left foldである。(e1 op e2) op e3) op e4のように展開される。

template < typename ... Types  >
auto sum( Types && ... args )
{
    return (... + args) ;
}

int main()
{
    // ((1 + 2) + 3) + 4
    sum( 1, 2, 3, 4 ) ;
}

(e op ...)は、right foldである。e1 + (e2 + (e3 op e4))のように展開される。

template < typename ... Types  >
auto sum( Types && ... args )
{
    return ( args + ... ) ;
}

int main()
{
    // 1 + ( 2 + ( 3 + 4 ) )
    sum( 1, 2, 3, 4 ) ;
}

fold式には、単項fold(unary fold)と二項fold(binary fold)が存在する。

上記の、(... op e)と(e op ...)は、単項fold式である。

二項fold式とは、(e1 op1 ... op2 e2)のことである。op1とop2は同じfold演算子でなければならず、e1とe2のどちらか片方のみが未展開のパラメーターパックでなければならない。

e2がパラメーターパックである場合、left foldになる。e1がパラメーターパックの場合、right foldになる。

template < typename ... Types >
void sum( Types && ... args )
{
    // binary left fold
    auto a = ( 0 + ... + args ) ;
    // binary right fold
    auto b = ( args + ... + 0 ) ;

    // エラー、両方がパラメーターパック
    auto c = ( args + ... + args ) ;
    // エラー、両方が非パラメーターパック
    auto d = ( 0 + ... + 0 ) ;
}

fold式に使える演算子はfold演算子である。これは以下の通り。

    +  -  *  /  %  ^  &  |  =  <  >  <<  >>
    +=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=
    ==  !=  <=  >=  &&  ||  ,  .*  ->*

パラメーターパックが空の場合、一部のfold演算子については、以下のようにデフォルトの値が定められている。

Table N. Value of folding empty sequences
Operator Value when parameter pack is empty
* 1
+ int()
& -1
| int()
&& true
|| false
, void()
template < typename ... Empty >
void f( Empty ... e )
{// eは空のパラメーターパックとする

    auto x1 = ( e * ... ) ; // 1
    auto x2 = ( e + ... ) ; // int()
    auto x3 = ( e & ... ) ; // -1
    auto x4 = ( e | ... ) ; // int()
    auto x5 = ( e && ... ) ; // true
    auto x6 = ( e || ... ) ; // false
    auto x7 = ( e , ... ) ; // void()
}

これ以外のfold演算子で、空のパラメーターパックをfold式でパック展開しようとすると、ill-formedになる。

N4267: u8文字リテラル

charひとつで表現できるUTF-8文字リテラル。

char A = u8'A' ; // 0x41

主な使い方として、確実にASCII文字の数値をわかりやすいリテラルでソースコードに記述できる。

N4230: 名前空間のネスト

namespace A { namespace B { namespace C {
} } }

を、

namespace A::B::C {
}

のように書ける。

N4266: 名前空間と列挙子に属性

名前空間と列挙子に属性を指定することができる。C++14までは、文法上の問題で指定できなかった。

具体的には、[[deprecated]]を指定できるようになった。

namespace [[deprecated("Use new_lib")]] lib { }
namespace new_lib { }

enum struct E { value [[deprecated("Use VALUE.")]], VALUE } ;

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日は社内が盛り上がっていた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-11

Tarse Range-Based forがClangから取り除かれていた

C++1zには、N3994: Tarse Range-based forが提案されていた。これは、Range-based forで型を書かずにすむようになる小粒な新機能だ。

任意のコンテナーを受け取って、その要素をすべて標準出力に出力する関数テンプレートを書くとする。これは以下のように書ける。

template < typename Container >
void print( Container const & c )
{
    for ( typename Container::value_type & elem : c )
        std::cout << elem << '\n' ;
}

いちいち型を書くのが面倒だ。これにはautoを使えばよい。

template < typename Container >
void print( Container const & c )
{
    for ( auto && elem : c )
        std::cout << elem << '\n' ;
}

しかし、auto &&すら書くのが面倒ではないか。N3994では、auto &&を省略できる新機能、Tarse Range-based forを提案していた。これはClangとGCCで実装されていたが、今試すとSNV HEADのClangでは動かない。はてどうしたことか。

調べると、C++1zには採用されない見込みになったので、取り除かれたそうだ。

[llvm-project] Revision 222865

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-10

2014-11-post-Urbanaのレビュー: N4332-N4339

N4332: Networking Library Proposal (Revision 3)

Boost.Asioを土台にしたネットワークライブラリの提案。

N4333: Concepts Lite

Concept Lite TSのドラフト

N4334: Wording for bool_constant

std::integral_constantのエイリアステンプレート、bool_constantの提案。既存のtrue_typeとfalse_typeはbool_constantで書き直される。

template <bool B>
using bool_constant = integral_constant<bool, B>;

typedef bool_constant<true> true_type;
typedef bool_constant<false> false_type;

新しいクラステンプレートではなくエイリアステンプレートなので、integral_constantを期待している既存のコードでも互換性の問題は生じないはずだ。

N4335: C++ Extensions for Library Fundamentals, Working Draft

標準ライブラリに対する拡張TSのドラフト

機能テストマクロ、optional, any, string_view, polymorphic_allocator, memory_resource, futureの拡張、新しいアルゴリズムなど

N4336: C++ Extensions for Library Fundamentals, Version 2, Working Draft

N4335とは異なるが、これも標準ライブラリに対する拡張TSのドラフト。

not_fn、observer_ptr, container_erasure, ostream_joiner, GCDとLCMなど。

N4337: Editor's Report — Library Fundamentals TS

標準ライブラリに対する拡張TSのドラフト編集者の報告書。

N4339: Agenda and Meeting Notice for WG21 Concepts Meeting

2015年1月26日にBloombergで行われるConcept会議の日程表。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-post-Urbanaのレビュー: N4320-N4331

N4320: Make exception-specifications be part of the type system

例外指定を型システムに含める提案。

関数ポインターを経由した例外指定の偽装がコンパイル時に検出できるようになる。

void (*p)() throw(int);
void (**pp)() throw() = &p;   // エラー

struct S { typedef void (*p)(); operator p(); };
void (*q)() noexcept = S();   // エラー

N4321: Towards Implementation and Use of memory_order_consume

memory_order_consumeの効果とLinuxカーネルでは使いにくい問題点などを解説したうえで、Linus Torvaldsでも満足する機能を設計している。

N4322: Linux-Kernel Memory Model

LinuxカーネルにおけるメモリモデルをC++の規格と比較してまとめたもの。

N4323: Out-of-Thin-Air Execution is Vacuous

複数のスレッドからのメモリアクセスによって競合を起こした場合、まったく脈絡のない値が現れることが規格上許されている。しかし、全く脈絡のない値が現れるのは問題である。この虚空から現れいでたる(Out-of-Thin-Air)値についての具体例の考察。

N4324: Use Cases for Thread-Local Storage

タイトル通り、TLSの利用例

TLS(Thread Local Storage)は長年利用されているにもかかわらず、その必要性が一般に理解されていない。C++標準化委員会の会議においてすら、TLSの存在価値に懐疑的な意見が出された。SIMDやGPGPUの専門家はTLSの存在意義に懐疑的で、逆にベクトルループ内でTLSが正しく動かないことに不満を持つものもいる。

この文書はその意見に答えて、TLSの既存の利用例や、SIMDやGPGPUにおけるTLSサポートの難しさ、TLSの代替機能などを考察している。

TLSの利用例として、例えばLinuxカーネルでは、CPUごとに必要な変数としてTLSを用いている。CPUごとに500以上もの静的なTLS変数と、100以上の動的なTLS変数が存在する。

TLSの最も主要な利用例としては、統計カウンターである。スレッドごと、CPUごとにカウンターを分割して、個別にカウンターを更新した後、最後に加算してすべてのスレッドのカウンターの値を得る。

TLSの他の利用例としては、オーバーヘッドの低いログやトレースを実装するために使われている。

TLSはメモリーアロケーターのスレッドごとのキャッシュにも使われている。

等など

なぜTLSはSIMDやGPGPUでは問題になるのか。TLSを初期化、破棄するにはコストがかかる。特にTLS変数がコンストラクターやデストラクターを持つ場合は、ミリ秒単位の時間が使われるかもしれない。これは、ひとつの実行単位がマイクロ秒単位のSIMDにとっては、無駄が多すぎる。GPGPUの実行単位はもう少し長いが、それでも問題だ。GPGPUの場合は、実行媒体が非常に多いので、GPGPUスレッドごとにTLS変数を作るのは、メモリーフットプリント上好ましくない。

TLSとSIMD/GPGPUは共存できるのか。SIMDレーンごとにTLS変数を初期化破棄するのはいかにも無茶だ。しかし、SIMDベクトルループ内でTLS変数の利用を禁止すると、従来のライブラリ、とくにerrnoに依存するようなライブラリが軒並み使えなくなってしまう。

N4325: C++ Standard Evolution Active Issues List
N4325: C++ Standard Evolution Completed Issues List
N4337: C++ Standard Evolution Closed Issues List

C++に提案中の新機能に対する議論中の問題、解決済みの問題、却下された問題の一覧。

N4328: C++ Standard Library Issues History for C++14

標準ライブラリのC++14に対する更新履歴の一覧。なかなか新しい文書だ。さすがに更新履歴が長くなってきたから分離したのだろうか。

N4329: C++ Standard Library Active Issues List
C++ Standard Library Defect Report List
N4331C++ Standard Library Closed Issues List

標準ライブラリで議論されている問題、解決済みの問題、却下された問題の一覧。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴにはボルダリング部があり、毎週水曜日に部員は仕事後にボルダリングに行っている。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-09

2014-11-post-Urbanaのレビュー: N4310-N4319

N4310: Technical Specification for C++ Extensions for Parallelism, Working Draft

Parallelism TSのドラフト

[PDf] N4311: Parallelism TS Editor's Report

Parallelism TSの編集者の報告書

[PDF] N4312: Programming Languages -- Technical Specification for C++ Extensions for Parallelism

N4311と内容は同じ。

N4313: Improvements to the Concurrency Technical Specification, revision 1

<future>にwhen_all, when_any_result, when_any, make_ready_future, make_exceptional_futureを追加する提案。

N4314: Data-Invariant Functions (revision 2)

入力の値におって、処理時間が異なるなどの外部から計測可能な挙動の違いが存在する場合、外部からその違いを計測することによって、秘密の情報が漏れてしまうことがある。暗号処理の実装において、サイドチャネル攻撃として知られている問題だ。

最近のOpenSSLのパッチは、そのような問題に対処するために入力によって処理速度が変化しないようにプラットフォーム依存の方法で対処している。

そのような仕組みは標準に存在するべきである。この論文では、入力の値によって外部から計測可能な挙動の変化が生じないような基本的な演算を提供するライブラリ、std::constant_time::value<T>を提供している。

// 入力の値によって処理時間やメモリアクセスパターンに差がでないことが保証されている
auto equal( std::constant_time::value<int> a, std::constant_time::value<int> b )
{
    return a == b ;
}

N4315: make_array, revision 3

std::arrayを作るstd::make_arrayの提案。

// 面倒
std::array<int, 5> a1 = { 1, 2, 3, 4, 5 } ;
// 簡単
auto a2 = std::make_array( 1, 2, 3, 4, 5 ) ;

// 面倒
atd::array<char, 4> a3 = { 'a', 'b', 'c', '\0' } ;
// 簡単
auto a4 = std::to_array("abc") ;

// std::array< char const *, 1 >
auto a5 = std::make_array("abc") ;

これは自分で実装してみるとVariadic Templatesの練習になって面白い。

リファレンス実装が公開されている。

N4316: std::rand replacement, revision 2

std::randの代替品、std::randintの提案

前回の変更点は、seed関数がseed_initからreseedに解明されたことだ。

[PDF] N4317: New Safer Functions to Advance Iterators

イテレーターを進めるadvanceとnextとprevに終端をチェックする安全版を追加する提案

例えば、イテレーターを三つ進めるごとに処理をしたいとする。以下のように書くと問題がある。


for ( auto i = begin(con), e = end(con) ; i != e ; std::advance( i, 3 ) ) 
    process( *i ) ;

このループは、イテレーターを三回進めるごとに終端のチェックを行っている。イテレーターの指す要素の数によっては、終端を飛び越してしまう可能性がある。

終端をチェックしつつイテレーターを進めるadvance, next, prevを追加しようという提案。この提案を使えば、以下のように書ける。


for ( auto i = begin(con), e = end(con) ; i!= e ; std::advance( i, e, 3 ) )
    process( *i ) ;

advance, next, prevに、終端のイテレーターを取るオーバーロードが追加される。

[PDF] N4318: Proposal to add an absolute difference function to the C++ Standard Library

絶対値の差を計算するabs_diff(a, b)の提案。

operator <とoperator -をサポートする型のオブジェクトの絶対値の差を計算してくれる。

int main()
{
    // 2
    std::cout << abs_diff( 3, 5 ) << '\n' ;
}

従来のabsでこれをやろうとすると、abs(a - b)のようになる。しかし、もし型が符号なし整数型で、bの方が大きい場合、悲惨なことになる。


int main()
{
    std::cout << abs( 3 - 5 ) << '\0' ;
}

結果は好ましい物にならないだろう。

[PDf] N4319: Contracts for C++: What are the Choices

会議の結果、contract programming(契約プログラミング)をコア言語で直接サポートすべきという意見に固まったが、contractに対するそれぞれの意見や経験がバラバラである。Microsoftの既存の経験から、contractの土台を解説している。

なぜcontractが必要なのか。

  • 実行時チェックによって予期しないプログラムの挙動を早期に発見できる
  • テストのサポート
  • 関数とデータ構造のドキュメント
  • 静的に証明可能な契約による最適化
  • 静的解析によるコンパイル時にバグの発見

contract systemに求めるもの

  1. あるコードに対する要求(required)と保証(ensured)を直接表現できること。たとえば、関数を呼び出す前と呼び出した後の条件や、通常時と異常時の挙動など。
  2. アノテーションによるオーバーヘッドを最小化する。contractは既存の機能と強調して働き、将来の発展を妨げるものであってはならない。
  3. 静的と動的な解析ツールや、コンパイラーの最適化の役に立つ
  4. あまりに冗長な文法ではないこと

論文著者は、contractが受け入れられるには、軽量な文法であることが必要であるとしている。

論文は、既存のマイクロソフト製品におけるContract機能を紹介している。

.NETのCodeContracts

public void TurnReactorOn()
{
    Contract.Requires(this.state == State.Off);
    Contract.Ensures(this.state == State.On);
    ...
}

このコードは、関数が呼び出される前はreactorが動いていないことを要求し、関数が呼び出された後はreactorが動いていることを保証するものである。これはライブラリで実装されている。実行時のチェックと、静的解析ツールによるチェックが行われる。

SAL

SALはプリプロセッサーマクロを多用した契約の記述だ。

void * memcpy(
_Out_writes_bytes_all_(count) void *dest,
_In_reads_bytes_(count) const void *src,
size_t count
);

この宣言は、destに書き込まれるバイト数とsrcから読み込まれるバイト数のアノテーションだ。MSはSALにより数多くのバグを発見して修正できているとしている。

System C#

System C#はC#の拡張で、言語機能としてcontractをサポートしている。

public string Format(int x)
requires x >= 0
ensures return != null
{
...
}

このコードは、関数が呼び出される前に、xが0ではないことを要求し、関数の戻り値がnullではないことを保証している。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-post-Urbanaのレビュー: N4301-N4309

[PDF] N4301: Working Draft, Technical Specification for C++ Extensions for Transactional Memory

トランザクショナルメモリーのTSドラフト

[PDf] N4302: Technical Specification for C++ Extensions for Technical Specification for C++ Extensions for Transactional Memory

N4301とほぼ同一。

N4303: Pointer safety and placement new

以下のコードは、C++14で挙動が定義された。

#include <new>
#include <cassert>

struct A { char buf[1]; };
struct B { char buf[1]; };

int main(void) {
    A a{ { 0 } };
    B *bp = static_cast<B *>(static_cast<void *>(&a));
    new (bp) B{ { 1 } };
    assert(bp->buf[0] == 1);
}

C++14では、static_castはaの先頭アドレスを指すことが明記されたので、上のコードは動作する。

ただし、これによって、コンパイラーのポインターの値によるエイリアシングの判定に誤りが生じる。そこで、この論文では、launderという関数を追加している。この関数にポインターの値を通すことによって、コンパイラーのアドレス値の解析を阻止するのだとか。

template <typename T> constexpr T* launder(T* p) noexcept;
Required behavior: An invocation of this function may be used in core constant expressions whenever the value of its argument may be used in a core constant expression.

Requires: p represents the address A of a byte in memory and an object Obj whose cv-unqualified type is remove_cv_t<T> is located at the address A.

Returns: A value of type T * which points to Obj.

そういう明示的なものが使われるとは思えない。

N4304: C++ Standard Core Language Active Issues
N4305: C++ Standard Core Language Defect Reports and Accepted Issues
N4306: C++ Standard Core Language Closed Issues

コア言語で現在議論中の問題、解決済みの問題、却下された問題の一覧。

[PDF] N4307: National Body Comment -- ISO/IEC PDTS 19568 -- Technical Specification: C++ Extensions for Library Fundamentals

Library Fundamentals TSに対するNBコメント集。日本からはmake_applyの追加というコメントが出ている。

[PDF] N4308: National Body Comment -- ISO/IEC PDTS 19570 -- Technical Specification: C++ Extensions for Parallelism

Parallelism TSに対するNBコメント集。

Return type deduction for explicitly-defaulted and deleted special member functions

特別なメンバー関数をdefault化、delete定義するときに、戻り値の型推定を許す提案。

以下のコードが、

struct X
{
    X & operator = ( X const & ) = default ;
    X & operator = ( X && ) = delete ;
}

以下のように書ける。

struct X
{
    auto operator = ( X const & ) = default ;
    auto operator = ( X && ) = delete ;
}

うーん・・・・、なんとも言いがたい。あって邪魔にはならない機能だが。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-08

2014-11-post-Urbanaのレビュー: N4293-N4298

N4293: C++ language support for contract programming

contractを言語でサポートする提案で、Urbanaの会議で議論した方針の結果をまとめたもの。

contractとは、処理を実行する上での前提条件(古典的にはassertマクロなどでチェックされていたもの)、処理を実行したあとの状態の保証、ある型の値は有効な状態になっていることだ。

これらのcontractは、既存のコードでは、assertマクロや、戻り値や例外などのエラー処理で処理されたりするものもあれば、単に未定義の状態になるとして済ませているものもある。

現在議論中のcontractは、コア言語によるサポートを必要とするものだ。ライブラリによる実装では、関数の本体の中に隠れてしまい、コンパイラーやツールからは使いにくくなってしまう。

ビルドモード(デバッグビルドやリリースビルドなど)を規格に含めるかどいうかという議論では、この提案では含めないということになった。

論文で提示されている文法は、提案する機能を示す目安であって、具体的な提案ではないが、例えば以下のような機能が欲しいとしている。

double square_root( double x )
expects( x >= 0.0 )
ensures( square_root >= 0.0 )

この例では、square_rootという関数のdouble型の実引数xは、必ず0.0以上であることを前提条件としていて、この関数の戻り値は必ず0.0以上であることを保証している。ensuresの中で関数名を使うと、関数の戻り値の意味になる。

これはあくまでこのような機能が欲しいという例示のための文法だ。

N4294: Arrays of run-time bounds as data members

実行時にサイズの決まる配列をクラスのデータメンバーとして持つことができる機能の問題点の洗い出しと解決案。

自動ストレージ、つまりスタックから実行時に決定されるサイズのストレージを確保したいという需要はあるが、C++風に型システムの上にサポートするには色々と問題があり、C++14では頓挫した。

既存の方法としては、alloca()とかC99のVariable Length Array、Flexible Array Memberなどがある。

int good_old_C()
{
    // スタックから確保
    // 低級すぎる
    void * p = alloca(100) ;
}

// C99
void vla( std::size_t size )
{
    // Variable Length Array
    // クラスによるラップができない
    char buf[size] ;
}

// C99
// Flexible Array Member
struct FAM
{
    std::size_t size ;
    char buf[] ;
} ;

void fam( std::size_t size )
{
    FAM * ptr =(FAM *) std::malloc( size ) ;
    ptr->size = size ;
}

C++でも実行時サイズ配列をサポートしたいが、型システムの中でやりたい。

前回の提案は、クラスの最後のデータメンバーが実行時サイズ配列で、クラスの最初のデータメンバーがconstな整数型でなければならず、最初のデータメンバーが実行時サイズ配列の要素数の指定に使われ、最初のデータメンバーの初期化が特別に扱われるというものだった。

// 前回の提案
struct X
{
    std::size_t size ;
    char buf[] ;

    X( std::size_t size ) : size(size), buf[size] { }
} ;

sizeの初期化は、通常のメンバーの初期化とは別に扱われる。

今回の提案では、配列コンストラクターという文法を提案している。

// 実行時サイズオブジェクト
struct X
{
    // 配列コンストラクター
    X[]() : buf[10] { }
    X[]( std::size_t size ) : buf[size] { }

    char buf[] ; // 実行時サイズ配列
} ;

配列コンストラクターはinlineでなければならない。

配列コンストラクターから通常のコンストラクターに転送することもできる。これはC++11の機能だ。

struct X
{
    // 配列コンストラクター
    X[]() : buf[10], X{} { }
    X[]( std::size_t size ) : buf[size], X{size1} { }

    // 通常のコンストラクター
    X() { }
    X( std::size_T size) { }

    char buf[] ; // 実行時サイズ配列
} ;

転送せずに、配列コンストラクターだけですべてを済ませることもできる。ただし、配列コンストラクターはinlineでなければならない。

今回の提案では、実行時サイズ型と実行時サイズオブジェクトに対してsizeofは一切サポートされない。

実行時サイズ配列の提案は文法や機能の設計がめまぐるしく変わっている。これもまだ決定ではないので、まだ変わるだろう。

sizeofがサポートされないのであれば、ある型が実行時サイズ型であるかどうかを調べるtraitsが欲しいところだ。

N4295: Fold expressions

Folding Expressionの文面案。

Folding Expressionとは、パラメーターパックpに対して、p + ...と書くと、p1 + (p2 + (p3 + p4))のように展開してくれる式のことだ。

例えば、実引数をすべて足し合わせる関数テンプレートsumを書きたいとする。従来ならば、以下のように書ける。

// 従来のパック展開による実装
template < typename T >
auto sum( T && t )
{
    return std::forward<T>(t) ;
}

template < typename T, typename ... Types >
auto sum( T && t, Types && ... args )
{
    return t + sum( std::forward<Types>(args) ... ) ;
}

見ての通り、極めて冗長だ。Folding Expressionを使えば、以下のように簡潔に書ける。

// Folding Expression
template < typename ... Types >
auto sum( Types && ... args )
{
    return args + ... ;
}

なお、ClangのSVNにすでに実装されているようだ。

Clang - C++1z, C++14, C++11 and C++98 Status

これはかなり確実に入りそうだ。

N4296: Working Draft, Standard for Programming Language C++

現在の最新のC++標準規格のドラフト

N4297: Editor's Report -- Working Draft, Standard for Programming Language C++

ドラフト編集者の編集報告書。

N4298: Agenda and Meeting Notice for WG21 Ballot Resolution Telecon Meeting

2014年12月5日に行われた電話会議の予定表。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-post-Urbanaのレビュー: N4280-N4288

N4280: Non-member size() and more (Revison 2)

フリー関数として、size, empty, dataを追加する提案。

template < typename Container >
void f( Container c )
{
    size(c) ;
}

int main()
{
    vector<int> v = { 1, 2, 3 } ;
    f( v ) ;
}

[PDF] N4282: A Proposal for the World's Dumbest Smart Pointer, v4

スマートではないスマートポインター、observer_ptrの提案。

observer_ptrは、生のポインターのクラスによるラッパーである。unique_ptrやshared_ptrとは違い、observer_ptrはポインターを所有しない。論文では、生のポインターを使うより、コード上でポインターの利用がわかりやすくなると主張している。

N4284: Contiguous Iterators

連続したストレージ上を指すイテレーター、Contiguous Iteratorsの文面案。

Contiguous Iteratorsは、デリファレンスできるイテレーターaと整数値nにおいて、*(a + n)が、*(addressof(*a) + n)と同等になる。

この提案では、新しいイテレータータグを追加するようなことは、下位互換性を壊す恐れから行わない。単に文面上での規程にとどまっている。

標準ライブラリのうち、連続したストレージが保証されているコンテナーは、vector, string, valarray, arrayである。

N4285: Cleanup for exception-specification and throw-expression

例外指定の文面を修正する提案。文面の整理が目的で、意味上の変更はない。

[PDF] N4286: Resumable Functions (revision 3)

中断可能な関数をコア言語でサポートする提案。

[PDf] N4287: Threads, Fibers and Couroutines (slides deck)

スレッドとファイバーとコルーチンについての発表のため、Urbana会議で使われたスライド資料。

N4288: Strike string_view::clear from Library Fundamentals

string_view::clearを文面から削除する提案。

ドワンゴ広告

この生地はドワンゴ勤務中に書かれた。

社内ポータルが一通り完成してきたようだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-05

2014-11-post-Urbanaのレビュー: N4270-N4279

やはり欠番が多い。

N4270: Consolidated Revisions to C++ Extensions for Library Fundamentals

標準ライブラリに対する拡張。

  • std::functionのswapは、アロケーターは交換しないという文面の追加。
  • BM法による検索アルゴリズムの追加
  • optional
  • any

[PDF注意] N4272: Working Draft, Technical Specification for C++ Extensions for Transactional Memory

トランザクショナルメモリーのドラフト文面

N4273: Uniform Container Erasure (Revision 2)

一部のコンテナーは、効率化のため、eraseをメンバー関数として提供している。任意のコンテナーから汎用的かつ効率的に要素を削除できる、erase_if( container, pred )とerase( container, value )の提案

template < typename Container >
void remove_less_than_100( Container & c )
{
    // 100以下の要素を削除する
    std::erase( c, []( auto v ) { return v < 100 } ) ;
}

[PDF注意] N4274: Relaxing Packaging Rules for Exceptions Thrown by Parallel Algorithms - Proposed Wording (Revision 1)

N4157における並列アルゴリズムで例外をパッケージ化する際の制限緩和の修正案は十分ではなかったので、完全問題を修正する新しい文面案。

N4275: Parallelism PDTS Comment Responses

並列アルゴリズムのTSに対するNBコメントへの返答。日本からは4件送っている。

N4276: Adding Fused Transform Algorithms to the Parallelism TS

並列アルゴリズムとして、transform_reduce, transform_exclusive_scan, transform_inclusive_scanを追加する提案。

N4277: TriviallyCopyable reference_wrapper (Revision 1)

reference_wrapperをTrivially Copyableにする提案。

N4279: Improved insertion interface for std::{unordered_,}map (revised)

std::mapとstd::unordered_mapについて。

emplaceは、要素が存在するときは何もしないが、規格準拠な実装は実引数をムーブしてもよい。ムーブをしないことが保証されたtry_emplaceを追加する。

要素が存在しない時は挿入し、存在するときは代入する、insert_or_assignを追加する。

ドワンゴ広告

今日は軽い論文と欠番がが多かったのでだいぶたまっている論文を消化できた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-post-Urbanaのレビュー: N4260-N4269

どうも欠番が多い。

N4261: Proposed resolution for Core Issue 330: Qualification conversions and pointers to arrays of pointers

多次元ポインターでconstを付け加える型変換について規定する文面がないため、以下のコードが違法になってしまう問題を修正する提案


  int main()
  {
     double *array2D[2][3];
  
     double       *       (*array2DPtr1)[3] = array2D;     // 合法
     double       * const (*array2DPtr2)[3] = array2DPtr1; // 合法
     double const * const (*array2DPtr3)[3] = array2DPtr2; // 違法
  }

規格の文面上にこの例についてカバーする箇所がないため、このようなことになってしまっている。

N4262: Wording for Forwarding References

テンプレート仮引数Tで実引数T &&や、auto &&は、どんな型でも受け取ることができる。この性質に対して、Fowarding Referenceという名前を付ける提案の文面案。

N4263: Toward a concept-enabled standard library

Concept Lite TSがほぼ完成したので、さっそく標準ライブラリをConceptに対応させたい。その対応させる際の方針を示した論文。

多少の非互換性は許容する方針らしい。たとえば、暗黙の型変換とか。

N4265: Transactional Memory Support for C++: Wording (revision 3)

トランザクショナルメモリーの文面案

この前のC++WG JPの会議では、現在提案中のトランザクショナルメモリーは、ハードウェアネイティブのトランザクショナルメモリーに落とし込める設計ではないので、何を考えて設計したのかよくわからない。全然実用的ではないという意見であった。

N4266: Attributes for namespaces and enumerators

名前空間とenumeratorにattributeを指定できる文法を追加する提案。これまでは文法が規定されていなかったので、deprecatedを指定できなかった。

namespace [[deprecated("lib_v1 is deprecated. Use lib_v2 instead.")]] lib_v1 { }

enum struct Option { safe, fast, super_fast, dangerously_fast [[deprecated("It has issues. Don't use it")]] } ;

N4267: Adding u8 character literals

charのオブジェクトひとつで表現できる文字に限ったUTF-8文字リテラルを追加する提案の文面案。

用途としては、ASCII文字をリテラルで表現できる。


char c = u8"c" ;

N4268: Allow constant evaluation for all non-type template arguments

非型テンプレート仮引数に配列からポインターへの型変換や関数からポインターへの型変換などを許容する提案の文面案

今回は欠番が多い。N4269のタイトルは、「まともなコンパイラーはatomicを最適化しない」というもので、興味深いのだが、欠番となっている。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-post-Urbanaのレビュー: N4250-N4259

N4250: WG21 2014-10-24 Telecon Minutes

2014年10月24日に行われた電話会議の議事録。

N4251: WG21 2014-11 Urbana Minutes
[PDF注意] N4252: PL22.16 2014-11 Urbana Minutes

2014年11月の3-8日に行われたUrbana会議の議事録。

N4253: Language Support for Runtime Contract Validation (Revision 9)

高級なassertライブラリを追加する提案。

N4254: User-Defined Literals for size_t (and ptrdiff_t)

size_tとptrdiff_tのユーザー定義リテラルを<cstddef>に追加する提案。

#include <cstddef>
int x = 0 ; // int
int s = 0z ; // std::size_t
int p = 0t ; // std::ptrdiff_t

整数リテラルのデフォルトの型はintである。int型は符号付き整数型である。size_tやptrdiff_tは符号なし整数型である。size_tやptrdiff_tを扱うときに、整数リテラルをそのまま書いて演算や比較をしてしまうと、符号を混ぜて処理することになり、思わぬ誤りにつながる。そのため、型安全のためには、size_tやptrdiff_t型のリテラルがほしい。

N4255: Proposed resolution for US104: Allocator-aware regular expressions (rev 3)

正規表現ライブラリをアロケーターに対応させる提案。

Delimited iterators (Rev. 4)

本当の意味でのデリミターをサポートするostream_joinerを追加する提案。

ostream_iteratorに指定するデリミターは、実はサフィックスである。

vector<int> v = {1, 4, 6};
cout << "(";
copy(v.begin(), v.end(), ostream_iterator<int>(cout, ", "));
cout << ")"; // Oops! Prints (1, 4, 6, )

最後の要素の後にもデリミターが出力されてしまう。正しくデリミターを付加する、ostream_joinerを新たに追加する提案。

vector<int> v = {1, 4, 6};
cout << "(";
copy(v.begin(), v.end(), std::make_ostream_joiner(cout, ", "));
cout << ")"; // Prints (1, 4, 6) as desired

N4258: Cleaning up noexcept in the Library (Rev 3)

ムーブコンストラクターなど、標準ライブラリでnoexceptを必須にした関数でも、例外を投げたくなる状況がある。たとえばデバッグモードなど。そのため、規格の文面を、「例外を投げないことが推奨される」という文面に変える提案。

N4259: Wording for std::uncaught_exceptions

現在まだキャッチされていない例外の数を返すint std::uncaught_exceptions() noexceptの文面。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

社内で勃発したきのこたけのこ戦争はたけのこ陣営が勝利したようだ。解せないことだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-04

シェアハウスを作ってみたい

東京に来て、ほぼ一年たった。

東京に来てからこれまで、妖怪ハウスというシェアハウスに住んでいる。妖怪ハウスは住んでいて面白いところではあるが、職場から遠いという問題がある。各駅停車しか止まらない駅から電車に乗り、途中乗り換えを三回挟まなければ職場に到達できない。通勤時間も一時間はかかる。

どこか、職場の近辺にでも引っ越したいものだ。特に、ドワンゴでは、職場の5km圏内に住むと近距離手当が出る。歩いて通勤できる場所に住むというのは魅力的だ。

ただし、引越というものは、労力と金が多大にかかる。ましてや、ドワンゴの本社がある歌舞伎座タワー、つまり銀座の5km圏内というと、決して賃貸の相場も安くはない。

かつ、シェアハウスというのは面白いし、効率的でもある。

どこか銀座の5km圏内にシェアハウスでも立ち上げたいものだ。

しかし、シェアハウスを立ち上げるには、まず住人を集めて、物件を探さなければならない。シェアハウスに使える賃貸を探さなければならない上、広くないといけないので、初期費用だけでもそれなりにかかる。

難しい話だ。気長に考えておくとしよう。

2014-10-pre-Urbanaのレビュー: N4240-N4249

N4240: Improved insertion interface for unique-key maps (Revision 2)

std::mapとstd::unordered_mapにある要素の挿入あるいはemplaceするとき、すでに要素が存在する場合は、挿入やemplaceが行われない。しかし、以下のような問題がある。

std::map< int, std::unique_ptr<T> > m ;
m[0] = nullptr ;
auto ptr = std::make_unique<T>() ;
m.emplace( 0, std::move(ptr) ) ; // ムーブされるかどうかは未規定

bool b = ( ptr == nullptr ) ; // 結果は未規定

上記の例で、emplaceはすでにキーに対応する要素が存在するので、行われない。しかし、ライブラリの実装次第によっては、ムーブが行われる可能性がある。規格はこの挙動を規定していない。

N4240は、挙動の規定された新しいメンバーを追加しようという提案だ。

  • try_emplaceは、キーが存在する場合、何も挿入せず、ムーブも行わない。
  • insert_or_assignは、キーが存在しない場合は挿入し、存在する場合は代入する
std::map< int, std::unique_ptr<T> > m ;
m[0] = nullptr ;
auto ptr = std::make_unique<T>() ;

// 戻り地はpair<iterator, bool>
auto result = m.try_emplace( 0, std::move(ptr) ) ; // 何もしない。ムーブemされない

bool b = ( ptr == nullptr ) ; // false

result.first ; // キーに対応する要素へのイテレーター
result.second ; // false, 挿入が行われたかどうか。

N4241: A proposal to add shared_mutex (untimed) (Revision 3)

従来のshared_mutexはtimed lock要求を満たすため、shared_timed_mutexに解明されたことを受けて、timed lock要求を満たさないshared_mutexの提案。

N4242: Executors and Asynchronous Operations, Revision 1

スレッドプールなどの方法で細かいタスクを並列実行するライブラリの設計の提案。N3785とは違い、だいぶ軽い設計になっている。

N4243: Networking Library Proposal (Revision 2)

Boost.Asioを土台にしたネットワークライブラリの提案。

N4244: Resumable Lambdas: A language extension for generators and coroutines

resumable lambdaの提案。

N4245: C++ Standard Library Active Issues List
N4246: C++ Standard Library Defect Report List
N4247: C++ Standard Library Closed Issues List

標準ライブラリに持ち上がっている既知の問題、修正済みの問題、却下された問題の一覧。

N4248: Library Preconditions are a Language Feature

関数の実引数に対して、呼び出し側が満たすべき前提条件を記述できるコア言語の文法が必要であるとする提案。

まだ具体的な文法は定まっていないが、なぜ前提条件のチェック、制約が必要なのかや、既存の例について長文で考察している。

N4249: Networking Primitives: std::experimental::network::htonl Considered Harmful

N4023はhtonl, ntohl, htons, ntohsというライブラリを提案している。これはかの有名なバークレーソケットAPIと同じように機能する。すなわち、バイトオーダーの変換を行う。

問題は、既存の実装は、大方がプリプロセッサーマクロで提供されているということだ。C++の標準ライブラリに同名の関数を持ち込むと、既存のコードと衝突する。標準C++をサポートするための移行にかかる労力は非現実的なものとなる。

N4249は、標準ライブラリでhtonlのような名前を使うのをやめるべきであると提案している。

かなしい。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

最近、社内にポータルができつつある。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-12-03

2014-10-pre-Urbanaのレビュー: N4230-N4239

N4230: Nested namespace definition (revision 2)

namespace A::B::C {
    // ...
}

を、

namespace A {
    namespace B {
        namespace C {
            // ...
        }
    }
}

と同等にする提案。

これは個人的に入るべき小粒な機能だと思う。

N4231: Terms and definitions related to "threads"

規格における「スレッド」の意味するところに意見の不一致が見られるので、スレッドの意味を明確に定義する。また、スレッドより軽い実行媒体についても定義する。

N4232: Stackful Coroutines and Stackless Resumable Functions

コルーチンとレジューム可能関数には似通った部分があるから統一してはどうかという意見に対し、コルーチンとレジューム可能関数の違いを解説している文書。

N3985が提案しているコルーチンは、ライブラリである。スタックフルな実装であり、アドレス空間を多大に消費する。ライブラリなので今すぐに使うことができる。

N3858, N3977の提案しているレジューム可能関数は、コア言語機能である。スタックレスな実装であり、コルーチンのようにアドレス空間を浪費しない。コンパイラーによるサポートが必要である。

N4233: A Class for Status and Optional Value

N3533で提案されているConcurrent Queuesライブラリでは、値と状態を別々に返すように設計されている。

Value queue::value_pop();
queue_op_status queue::try_pop(Value&);
queue_op_status queue::nonblocking_pop(Value&);

この設計には、以下の制約がある。

  • value_popで状態が悪い場合、例外が投げられる
  • try_popとnonblocking_popを使う場合、Valueがデフォルト構築可能でなければならない

なにか状態と値を同時に返せるようなライブラリが欲しい。そう、例えば以下のような。


something<queue_op_status, Value> queue::value_pop();
something<queue_op_status, Value> queue::try_pop();
something<queue_op_status, Value> queue::nonblocking_pop();

設計上の要件としては、このsomethingは、必ず状態を有するが、値を有するかどうかは分からない。存在しない値にアクセスしようとすると例外を投げる。

これは提案中のoptionalやexpectedに似ている。ただし、optionalとexpectedは、値かエラーかのどちらか片方を格納するライブラリである。ここで欲しいのは、必ず状態を格納し、値を格納しているかどうかは分からないライブラリだ。

N4233は、このような要求を満たす、status_value< Status, Value >というライブラリを提案している。

N4234: 0-overhead-principle violations in exception handling - part 2

ゼロオーバーヘッドの原則(Zero Overhead Principal)とは、使わない機能のオーバーヘッドを支払うべきではないという原則である。ある機能があったとして、その機能を使わない場合、その機能をサポートするために必要なオーバーヘッドがもたらされてはならない。C++は伝統的に、この原則を強く意識してきた。Bjarne StroustrupがSimulaを使ってシミュレーターを書いたら、使いもしないGCのオーバーヘッドでプログラムの実行時間の80%が浪費されていたことは、あまりにも有名だ。

C++で、特にオーバーヘッドのやり玉に上げられるのは、例外である。例外のオーバーヘッドについては、N4049で考察されている。組み込みなどの資源制約の厳しい環境では、例外のオーバーヘッドは高く付きすぎる。

この論文、N4234では、もしユーザーが例外を使わずにSTLを用いた場合、規格と現在の実装は、現在の最適化技術であWhole Program AnalysisやLink Time Optimizationを用いて、例外によるゼロオーバーヘッドの原則(生成されたバイナリに例外サポートのためのコードが一切含まれないことを指す)を尊重できるのかどうかを考察している。

論文は、例外を使わないコンパイラーフラグや、例外を使わないSTL実装を使うことについては考察していない。

例外処理サポートのない特別なSTL実装の使用(gccの-fno-exceptionsフラグなど)は考察しない。例外処理は言語の一部であり、言語のサブセットを定義することは、過去にEmbedded C++があったように、好ましいことではない。

この論文では、以下のようなプログラムで実験を行った。

  • ::operator new(nothrow)を呼ぶアロケーター
  • main関数
  • noexceptではないvector::push_backの呼び出し
  • 純粋仮想関数が誤って呼ばれた場合に呼ばれる関数(__cxa_pure_virtual)を、ツールチェインの例外を使うデフォルト実装を上書きして定義する(ドキュメント化された方法である)

ターゲットプラットフォームはLinux x86-64(Ubuntu 14.04)で、GNUツールチェインが用いられた。Clangでも試したらしいが、同じ結果だったそうだ。

結果としては、生成されたバイナリには、例外サポートのためのシンボルが含まれていた。

理由はいくつかある。STL実装の内部で、_M_check_lenという関数が呼ばれ、これがlength_error例外を投げている。範囲外かどうかのチェックは規格で必須になっているため、これは規格準拠の実装である。operator new(nothrow)は、例外を使ってnew_handlerから投げられる例外を確認している。

_GLIBCXX_WEAK_DEFINITION void * 
operator new (std::size_t sz, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT 
{ 
  void *p; 
 
  /* malloc (0) is unpredictable; avoid it.  */ 
  if (sz == 0) 
    sz = 1; 
 
  while (__builtin_expect ((p = malloc (sz)) == 0, false)) 
    { 
      new_handler handler = std::get_new_handler (); 
      if (! handler) 
        return 0; 
      __try 
{ 
  handler (); 
} 
      __catch(const bad_alloc&) 
{ 
  return 0; 
} 
    } 
 
  return p; 
} 

なぜこんなコードでなければならないかというと、規格でoperator new(size)を呼び出すようになっているからだ。そして、operator new(size)は以下のように定義されている。

  • ループを実行する。ループの中で、まず要求されたストレージの確保を試みる。ストレージ確保の方法は実装依存である。
  • ストレージの確保が成功したならば、ストレージへのポインターを返す。ストレージの確保が成功しなかった場合で、現在のnew_handlerがnullポインターの場合、std::bad_allocをthrowする。
  • 現在のnew_handlerがnullポインター以外の場合、現在のnew_handlerを呼び出す。呼び出しが返ったならば、ループを続行する。
  • ループはストレージの確保が成功するか、new_handlerの呼び出しが返らなくなるまで、続けられる。

私が書いたC++11の文法と機能も参照。

operator newは、ストレージの確保に失敗した場合、new_handlerを呼び出してから、再びストレージ確保を試みる。new_handlerがループを打ち切ると判断したかどうかは、例外を使わなければ確認できない。

アロケーターでoperator new(nothrow_t)のかわりに、mallocを使ったプログラムの場合、例外サポートのためのシンボルを含まないバイナリの生成に成功したという。

このテスト結果を受けて、論文では、規格に以下のような改善案を提示している。

STLに対する改善案としては、

コンテナーにnoexcept版のメンバー関数を追加する。

引数の違いで追加する方法

void push_back (const value_type& val,  nothrow_t ) noexcept; 
void push_back (value_type&& val,  nothrow_t ) noexcept;  

あるいは別名で追加する。

範囲外チェックをoptionalにする。

C++に対する改善案としては、

noexcept修飾子で、ポインターを修飾することを可能にする。これによってオーバーロード解決でnoexcept版のメンバー関数が呼ばれる。

論文にサンプルコードはないが、以下のような感じだろうか。

struct X
{
    void f() ; // エラーを例外で通知
    bool f() noexcept ; // エラーを戻り値で通知
} ;

int main()
{
    X noexcept x ;
    x.f() ; // noexceptのオーバーロードが呼ばれる。
}

うーむ・・・

new_handlerに対しては、例外を投げないnew_nothrow_handlerを追加する改善案が示されている。s

標準ライブラリに例外を投げないstd::nothrow_allocatorを追加する案も示している。

N4235: Selecting from Parameter Packs

テンプレートパラメーターパックを扱う際に、N番目の型を取り出したいことがよくある。これは以下のように書くことができる。

template<int N, typename T0, typename ... Tr> struct nth_type_impl {
  using type = typename nth_type_impl<N-1, Tr...>::type;
};
  template<typename T0, typename ... Tr>
  struct nth_type_impl<0, T0, Tr...> {
    using type = T0;
  };
template<int N, typename ... Ts>
using nth_type = typename nth_type_impl<N, Ts...>::type;

template<typename ... Ts> struct App {
  nth_type<3, Ts...> n1;  // 4番目の要素.
}

これは動く。動くのだが、問題がある。これは再帰的なテンプレートのため、テンプレートのインスタンス化が大量に発生し、コンパイラー資源の浪費である。また、エラーメッセージもわかりにくい。

N4235では、パラメーターパックを扱うための便利な文法をいくつか提案している。

パラメーターパックからN番目の要素を取り出す文法

先ほどのAppは、以下のように簡潔に書くことができる。


template < typename ... Ts >
struct App
{
    Ts.[3] n1 ; // 4番目の要素
} ;

存在しない場合はエラーになる。

template < typename ... Types >
struct first
{
    using type = Types.[0] ;
} ;

using type = first<>::type ; // ill-formed

パックサブセット、パラメーターパックTsからsizeof...(Ns)だけ切り出す文法

Ts.<Ns...>

先頭からsizeof...(Ns)だけ要素を切り出したパラメーターパックになる。

N番目の要素だけ指定して切り出す文法

Ts.<1, 3, 5>

これは、2番目と4番目と6番目の要素のパラメーターパックになる。

Ts.<0, Ns..., 0>

これは、前後を最初の要素に挟まれたTs.<Ns...>になる。

整数シーケンスのパック展開を簡単に作れる文法 b ... < eも提案されている。

// {1,2,3,4,5,6,7,8,9}
int digits = { 0 ... < 10 } ;

これは、パックサブセットと組み合わせると強力になる。

// 最初の要素を除いたパラメーターパック
Ts.< 1 ... < sizeof...(Ts) >
// 最後の要素を除いたパラメーターパック
Ts.< 0 ... < sizeof...(Ts) - 1 >
// 要素を二度繰り返したパラメーターパック
Ts.< 0 ... < sizeof...(Ts), 0 ... sizeof...(Ts) >

また、この文法をプリプロセッサーでサポートするためにpp-numberにも変更を加える提案をしている。

面白い機能だ。文法にバイク小屋議論はあるだろうが、このような機能は欲しい。

N4236: A compile-time string library template with UDL operator templates

C++の文字列リテラルは、C言語から受け継いだ。C++では、std::basic_stringによって、文字列操作を高級にした。しかし、まだC++における文字列は扱いづらい。論文では、以下のようなサンプルコードで例示している。


// 結合
  //
  auto x1 = "Hello" + ", " + "World!"; // エラー!
  auto x2 = std::string("Hello") + ", " + "World!"; // 動くけど汚い。あと実行時コストがかかる
  auto x3 = "Hello" + std::string(", ") + "World!"; // エラー!
  auto x4 = "Hello" ", " "World!"; // 動くけど・・けど・・・

  auto conjunction = std::string(", ");
  auto x5 = "Hello" conjuction "World!"; // けど、これはエラーだろ。

  // ジェネリックプログラミング
  //
  template <typename T>
  typename T::size_type find(T t, typename T::value_type q)
  {
      return t.find(q);
  }

  auto s1 = std::string("One");
  auto s2 = "Two";

  find(s1, 'n'); // これはいい
  find(s2, 'w'); // エラー!
  find(std::string(s2), 'w'); // うごくけど、ちょっと待てよオイ

  // テンプレートメタプログラミング
  //
  template <typename T> struct metaprogram { /* ... */ };

  metaprogram<"Hello, World!"> m1; // エラー!
  metaprogram<std::string("Hello, World!")> m2; // そもそもなんじゃこりゃ
  metaprogram<decltype("Hello, World!")> m3; // そういう意味じゃない
  metaprogram<decltype(std::string("Hello, World!"))> m4; // これも違う
  metaprogram<boost::mpl::string<'Hell','o, W','orld', '!'>> m5; // やったぜ! ってなめとんのかー!
  metaprogram<_S("Hello, World!")> m6; // 詳細は気にするな

この論文は、文字列リテラルを使いやすくするために、新しいテンプレートライブラリstd::basic_string_literalと、ユーザー定義リテラルを提案している。これにより、上のコードは、以下のように書ける。

  // 結合
  //
  constexpr auto x1 = "Hello"S + ", "S + "World!"S; // 動く。実行時コストなし

  constexpr auto conjunction = ", "S;
  constexpr auto x5 = "Hello"S + conjuction + "World!"S; // 動く、実行時コストなし。

  // ジェネリックプログラミング
  //
  template <typename T>
  constexpr typename T::size_type find(T t, typename T::value_type q)
  {
      return t.find(q);
  }

  auto s1 = std::string("One");
  constexpr auto s2 = "Two"S;

  find(s1, 'n'); // 動く。
  find(s2, 'w'); // 動く。実行時コストなし

  // Template Metaprogramming
  //
  template <typename T> struct metaprogram { /* ... */ };

  metaprogram<decltype("Hello, World!"S)> m1; // 動く、実行時コストなし

このライブラリ、std::basic_string_literalのコンストラクターはprivateである。std::basic_string_literalは、ユーザー定義リテラルoperator "" Sによってのみ構築することができる。実行時オブジェクトを誤って作り出してしまうことを防ぐためである。std::basic_string_literalは、std::basic_stringにインターフェースを似せて設計されており、const std::basic_string相当のことができるようになっている。

N4237: Language Extensions for Vector loop level parallelism

Clik PlusやOpenMP 4.0を土台にしたベクトルループをコア言語機能として追加する提案。プリプロセッサーではなくキーワードを使う。

int main()
{
    int a[100] = { ... };
    int b[100] = { ... };
    int c[100] = { ... };

    for simd ( int i = 0 ; i < 100 ; ++i )
    {
        c[i] = a[i] + b[i] ;
    }

}

ベクトルループには制約が多い。たとえば、上記のコードを説明する。

ここで、iはInduction Variableである。繰り返し文の条件では、< ,>, <=, >=, ==, !=のどれかを使わなければならず、しかもそのオペランドの片方は、識別子でなければならない。識別子はInduction Variableをささなければならない。for文の3つめのオペランドは、インクリメントやデクリメント、あるいはそれに準ずるような式(+=とかa = b + cとか)しか書けない。ループの本体でInduction Variableを書き変える場合は、インクリメントやデクリメントの類しか使えない。

ベクトルループには、チャンクサイズを指定できる。

for simd safelen(5) ( int i = 0 ; i < 10 ; ++i )
{
    X ;
    Y ;
}

ここで、式Xが式Yに先行しなければならない場合、i == 6の時の式Xの実行の前に、i == 5の時の式Yの実行は先行している保証がある。

とにかく制約が強いし、その制約を厳格に文面化するために、文面はかなりわかりにくい。

N4238: An Abstract Model of Vector Parallelism

並列実行版の<algorithm>で、純粋なベクトル実行ポリシーを設計するための、ベクトル実行の抽象的なモデルを提示する。この論文は提案ではない。

N4239: Defaulted Comparison Using Reflection

デフォルトの比較演算子をコンパイラーが生成しようという提案があるが、そういうものは現在提案されているリフレクション機能を使ってライブラリでやればよいという提案。

リフレクション機能が十分に柔軟であれば、比較演算子にとどまらず、+=とかhashの自動生成まで行える。また、比較方法について意見の一致が見られないので、なおさら多様な挙動を柔軟に切り替えられるライブラリでやるべきことだとの主張だ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日は、社内できのこの山派とたけのこの里派による宗教戦争が勃発したが、コーラタワー崩壊により終結したようだ。残念ながら、筆者は今回もコーラタワー崩壊を目にすることはかなわなかった。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-30

12月7日の日曜日に妖怪ハウスでボドゲ会

12月7日の日曜日に、妖怪ハウスでボードゲーム会を行うことにした。

特に時間を設けてはいないので、当日の何時に来てもよい。

今回はピザを焼く予定だ。

妖怪ハウスの住所は、中野区野方5-30-13 ヴィラアテネ401となる。


View Larger Map

2014-11-28

2014-10-pre-Urbanaのレビュー: N4220-N4229

[PDF注意] N4220: An update to the preprocessor specification (rev. 2)

プリプロセッサーの規格には、未定義な挙動とされている部分があるが、多くの主要な実装で似通った実装になっているところもあるので、その部分を規格で追認する。また、生文字列リテラルやユーザー定義リテラルなど、C++の新しい文法にプリプロセッサー規格が追いついていないので、対応させる。矛盾した点や曖昧点も改善する。

プリプロセッサーの定義に未定義な挙動が多いのは、実装に自由度をもたせたり、独自拡張を許可したりするためだったのだが、結局問題のある未定義の挙動は違法であると定義したほうがよいし、当時は独自拡張のために未定義にしていたところも、数十年たてば、主要な実装はほぼ似たような実装に落ち着いたりした。

[PDF注意] N4221: Generalized lifetime extension

寿命修飾子(lifetime qualifier)の提案。

一時オブジェクトの寿命は、完全な式の中である。

ただし、リファレンスに束縛された一時オブジェクトは寿命が延長される。

struct X { } ;

int main()
{
    // 一時オブジェクトの寿命が延長される。nn
    auto && ref = f() ;
}

しかし、関数呼び出しの結果返されるリファレンスに対しては、たとえ参照先が一時オブジェクトであったとしても、寿命延長が行われない。

struct X
{
    int data ;
    ~X()
    {
        std::cout << data <<  ": destructed.\n" ;
    }
} ;

int main()
{
    auto && r1 = X{1} ; // 寿命延長される
    auto && r2 = std::move( X{2} ) ; // 寿命延長されない

    std::cout << "end of scope.\n" ; 
}

なぜならば、関数の実引数として与える式がfull-expressionだから、その時点でmain関数のブロックスコープのリファレンスに束縛されていない以上、寿命延長されないのだ。関数を呼び出した結果のリファレンスは、たとえ一時オブジェクトを束縛していたとしても、寿命延長されない。

これにより、クラスのアクセッサー(getter)が使えず、データメンバーを直接publicで使わなければならないという問題もある。

struct X
{
    int data ;
    int & get_data() const { return data ; }
} ;

int main()
{
    auto && ref =  X{}.data ; // 寿命延長される
    auto && ref = X{}.get_data() ; // 寿命延長されない
}

ここで、dataはprivateなメンバーにして、publicがget_dataでアクセスさせたいとしても、寿命延長されないという点で使えない。

これが具体的に問題になるのは、例えばrange-based forだ。

struct has_vec
{
// これはprivateメンバーにしたい
    std::vector<int> m = { 1, 2, 3 } ;

    std::vector<int> & get_vec() const
    { return m ; }
} ;

int main()
{
    for ( int val : has_vec{}.m ) ; // OK
    for ( int val : has_vec{}.get_vec() ) ; // エラー、寿命延長されない
}

もっと具体的な例を挙げると、Boost.Adaptorsをrange-based forで使いたい場合がある。

std::vector<int> vec;
for (int val : vec  | boost::adaptors::reversed
                    | boost::adaptors::uniqued )
{
    // 一時オブジェクトはすでに破棄されている
}

関数を超えて一時オブジェクトの寿命を延長させるには、新しい言語機能が必要である。

関数の仮引数宣言に寿命修飾子(lifetime qualifier)であるexportキーワードを記述して、寿命を延長させることができる。

struct X { } ;
template < typename T >
T const & f( export T const & t )
{
    return t ;
}

int main()
{
    auto && ref = f( X{} ) ; // 寿命延長される
}

データメンバーを直接使わなければならない問題も、寿命修飾子により解決できる。

class has_vec
{
private :
    std::vector<int> m = { 1, 2, 3 } ;

public :
    std::vector<int> & get_vec() export const
    { return m ; }
} ;

int main()
{
    for ( int val : has_vec{}.get_vec() ) ; // OK
}

これにより、Boost.Adaptorsの例も動く。

[PDF注意] N4222: Minimal Additions to the Array View Library for Performance and Interoperability

連続したストレージを多次元配列に見せかけるライブラリarray_viewに対する機能追加の提案。

テンプレートで行が先か、列が先か、レイアウトを選べるようになる。

既存の似たようなライブラリからの移行を用意にするため、operator ()をサポート

operator []はレイアウトが行列どちらでも動作が変わらないようにする。

内部的なポインターにアクセスできるようにする。

特に1次元配列の場合だが、RandomAccessContainerとrangeのサポート。

N4223: Response To: Let return Be Explicit

N4074で提案された、return {expr}で暗黙の型変換がおこるときでもexplicitコンストラクターを呼び出せるようにする提案に対する反論。

explicitなものはexplicitなのだから制限を緩和すべきではないとしている。

N4224: Supplements to C++ Latches

N4204で提案されている同期ライブラリ、ラッチとバリアーに対する機能追加の提案。

ラッチのオブジェクトを安全に破棄するためには、そのラッチに対してwaitしているすべてのスレッドのブロックを解いてからでなければならない。これは、ラッチをローカル変数として確保している場合、そのスレッドはブロックスコープを抜ける前にwaitしなければならないことを意味する。

これを避けるために、以下の関数でSelf-Destructするラッチを生成できるようにする。

static latch* create_self_deleting( int C );

それから、ラッチの完了通知ができるようになった後、スレッドのブロックが解かれる間の状態のときに、呼び出されるコールバック関数を指定できる、flex_latchを追加する。

N4225: Towards uniform handling of subobjects

基本クラスをクラス定義の中で宣言できる機能の提案。

まだ大雑把な構想段階だが、たとえばこういうコードが書けるようになりたい。

struct Base
{
    Base( std::string ) ;
} ;

class Derived
{
members:
    string str = "hello" ;

public bases :
    Base{ str } ;

} ;

アクセス指定子の文法を拡張することで、基本クラスをクラス定義の中で指定できる。

しかも、基本クラスよりも上に書かれているデータメンバーの初期化の方が、基本クラスの初期化より先に行われるので、基本クラスの初期化に派生クラスのデータメンバーを使うことができる。

論文はとても短く、大雑把な構想しか記述していない。そして最後に、

この提案の目的は何か?

簡単に言えば、この提案は複数の欲しがられている機能を汎用的に提供できる、とても大雑把な構想だ。パーサーだとかそのへんの問題はいろいろあるだろうけど、とりあえず目安として、まず聞きたいことは、

  • We hate it?
  • We like it?

私はもっと具体的な利用例や需要が示されるまでは、いらないと思う。

[PDF注意] N4226: Apply the [[noreturn]] attribute to main as a hint to eliminate global object destructor calls

[[noreturn]]をmainに指定した場合、staticストレージのオブジェクトの破棄をしなくてもよいという意味にしようという提案。

組み込み環境など、mainから戻ることがなく、staticストレージ上のオブジェクトを破棄するコードすら許容できないような厳しい資源の制約のある環境の場合に役に立つ。

私は、別のattributeにしたほうがいいと思う。

[PDF注意] N4227: Cleaning-up noexcept in the Library (Rev 2)

N3279で、標準ライブラリにnoexceptを付ける際のガイドラインを設けた。

数年の経験を経た今、そのガイドラインを改良する必要がある。

問題なのは、デバッグモードでムーブコンストラクターが例外を投げる可能性だ。そこで、C++17では、std::stringのムーブコンストラクターからnoexcetptを取り除く決定がなされた。

しかし、一般にnoexceptを取り除きたくはない。そこで、ガイドラインでは、「noexceptにすることが大変望ましい」として、要求はしないようにする。

[PDF注意] N4228: Refining Expression Evaluation Order for Idiomatic C++

f( a, b, c ) のような式があった場合、sub-expressionであるf, a, b, cの評価順序は、規格上未規定である。もし、sub-expressonが同じオブジェクトを変更していた場合、プログラムの挙動は未定義になってしまう。f( i++, i ) や v[i] = i++ のような式の挙動は未定義である。

例えば、以下のコードは未規定である。

#include <map>
int main() {
    std::map<int, int> m;
    m[0] = m.size();
}

論文は言う、「この手の質問は、単なる娯楽ではなく、採用面接問題でもなく、学術的な興味によるものでもない。現在規格が規定する式の評価順序は、有害で、有名なプログラミングのイディオムに反し、標準ライブラリの安全な使用にも悪影響を与えている。この罠は素人や注意深くないプログラマーのみ引っかかるものではない。ルールを知っているものですら陥る。」

例えば、以下のコードだ。

void f()
{
    std::string s = “but I have heard it works even if you don’t believe in it”
    s.replace(0, 4, “”).replace(s.find(“even”), 4, “only”).replace(s.find(“ don’t”), 6, “”);
    assert(s == “I have heard it works only if you believe in it”);
}

このコードの挙動は未規定である。

ちなみに、このコードは世界的なC++エキスパート達から査読を受けた、The C++ Programingu Language 4th(プログラミング言語C++第四版)に存在するものである。最近、このコードの問題がツールによって発見された。

このコードを、トリッキーなメソッドチェイニングを使うから悪いのだと避難するのは当たらない。std::cout << a << b << cですらチェイニングである。また、std::future<T>にthen()メンバー関数を追加して、メソッドチェイニング的に使わせようと設計している今、問題はチェイニングではないのだ。根本的な問題を直さなければならない。

論文では、以下の評価順序を提案している。

  • postfix-expressionは左から右に評価される。これには関数呼び出しとメンバーアクセスも含まれる
  • 代入式は右から左に評価される。複合代入も含まれる
  • シフト演算子のオペランドは左から右に評価される

以下の式は、a, b, c, dの順に評価される。

  • a.b
  • a->b
  • a(b,c,d)
  • b=a
  • b@=a

また、オーバーロード演算子の評価順序は、関数呼び出しのルールではなくて、対応する組み込み演算子の評価順序に従う。

これは歓迎すべき提案のように思われる。sub-expressionの評価順序は定めるべきだ。

N4229: Pointer Ordering

標準ライブラリの関数オブジェクトの比較はtotal orderingを要求しているが、関数オブジェクトが関数ポインターの場合ですら適用されてしまう。ポインターに対する組み込みの比較はtotal orderingではないというのに。

関数ポインターの場合は、組み込みの比較と同じ結果になるように一文を加える修正。

ドワンゴ広告

この記事はC++WG JPの会議に出た後にドワンゴに出勤して書かれた。

今夜はボドゲでもしようとおもう。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

ドワンゴはFPGAの扱えるハードウェア開発エンジニアを募集しているようだ。

【ニコニコ事業】ハードウェア開発エンジニア (正社員)|職種一覧|中途採用・アルバイト採用・障がい者採用|採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-11-26

妖怪ハウスで12月にボドゲ会でもしようかと思うので日程を募集

妖怪ハウスで12月にボドゲ会をしようと思う。まだ日程を決めていない。いつがいいだろうか。

調整さん - 簡単みんなのスケジュール調整ツール

覆面銃武装マンの都合が日曜日なので、今回は日曜日にしようかと思う。

となると、7日、14日、21日のいずれかだが、いつがいいだろうか。週末まで上の調整さんで多数決を募りたい。

今回は、カレーに加えてピザも作ろうと思う。

2014-10-pre-UrbanaのC++標準化委員会文書のレビュー: N4210-N4219

[またPDF] N4210: IBM comment on preparing for a Trigraph-adverse future in C++17

トライグラフ除去の可否を問う投票で、賛成票が多数派であったが、その中でIBMは強く反対の立場であった。トライグラフは現に利用者がいて、ASCIIが多数派なC++では、マイノリティといえど、実際の利用者がいる機能を除去するのは、C++のためにならないという主張である。そこでBjarne Stroustrupから、その現実の利用者をまとめて報告せよと言われたので、IBMはこの文書を提出した。

IBMによれば、機密のため顧客名は明かせないものの、現実に利用者が多数いるという。特に重要な利用者の、ある北アメリカの大手の某銀行は、IBMメインフレームを使い続けている。処理は極めて重要である。彼らは長年の多大な労力をデバッグにつぎ込んでおり、安定していて、他の環境に移行することは決してない。

C++はASCIIが多数派であるが、物言わぬマイノリティの声を代弁するためにもIBMはトライグラフ除去に反対するという。

どうも私にはよくわからない世界だ。

N4211: File System TS Active Issues List (Revision R3)
N4212: File System TS Closed Issues List (Revision R3)
N4213: File System TS Defect Report List (Revision R3)

TSに提案されているFile systemライブラリに持ち上がっている問題集

[PDF] N4214: A Module System for C++ (Revision 2)

40年前のコピペ技術である#inludeにかわるモジュール機能の提案。

現在、C++が使っているコンパイルとリンクモデルは、C言語から受け継いだものである。各翻訳単位は、他の翻訳単位のことを一切知らずに処理される。翻訳単位を超えるには、名前リンケージ(シンボル名)を使う。名前に対応する定義はひとつだけでなければならない(ODR)。

翻訳単位の外に見える名前である外部名を、手動によるコピペで管理することを防ぐために、我々は40年前の技術である自動コピペ技術、プリプロセッサーによるヘッダーファイルを未だに使っている。これは、コンパイラーからみれば、コピペである。

ヘッダーファイルの中身はマクロによって書き換わってしまうおそれがあり、誤りの元である。

変数や関数の宣言ぐらいしか書かれていなかった昔のC言語ならば、まだ十分に耐えられたのだが、モダンなC++では、ヘッダーファイルには実行されるコードが記述されている。コンパイラーは翻訳単位ごとに重複した内容を処理しなければならず、現代のC++のコンパイル時間の増大の原因になっている。

この論文では、C++に近代的なコンポーネント化をもたらすための機能、モジュールの設計を考案している。

モジュールは、既存のプリプロセッサーと組み合わせて使うことができる。これは穏やかな移行のために必要である。既存のプログラムはプリプロセッサーによる自動コピペ技術でコンポーネント化されていて、自動的にモジュールに書き換わってはくれない。今後もしばらくはぷりプロセッサーを使う必要がある。この地上からプリプロセッサーを一掃して、純粋なモジュールのみを使う素晴らしき新世界になるまでは。

さて、モジュールの使い方だが、論文では以下のような文法を想定している。

import std.vector ; // #include <vector>

int main()
{
    std::vector<int> v ;
}

モジュールを使う側からすれば、#includeの機械的な置換ぐらいで対応可能だ。

では、ライブラリ側がモジュールに対応するにはどうすればいいのだろうか。これには二つの設計が考えられる。コンパイラー側が自動的に対応する方法と、ソースファイル中に宣言を記述するものだ。論文では、コンパイラーに推測させるよりも、明示的な宣言の方が好ましいとしている。

モジュールは、モジュール宣言で宣言する。

module module-name ;

この宣言の意味は、この翻訳単位のこれ以降の宣言は、module-nameという名前のモジュールの一部であるという宣言だ。モジュール宣言は翻訳単位に一つしか存在できない。前回の論文では、翻訳単位の最初の宣言でなければならないとしていたが、今回の論文では、そのような制約は必要ないということで緩和された。移行を簡単にするために、module宣言の前に宣言されているものは、グローバルモジュールに属するものになる。

モジュールによるインターフェース宣言は、実装と同じソースファイルに記述することもできるし、別のソースファイルに記述することもできる。これは、どちらか片方だけに制限するのは現実的ではないためだ。

モジュールは外部へのテントリーポイントを、export宣言で宣言する。

export toplevel-declaration
struct X { } ;
module M ;
struct Y { } ;

export struct Z { } ;

このように記述した場合、Xはグローバルモジュールに属する。YはモジュールMに属するが、エクスポートされていない。ZはモジュールMに属するexportされている名前だ。

toplevel-declarationは、import宣言かmodule宣言か、通常の宣言のいずれかである。export宣言にimport宣言を指定した場合、import宣言で指定したモジュールがエクスポートする宣言が、現在のモジュールから見えることになる。

module lib ;
export import std.vector ;

export namespace lib {

class Foo
{
    std::vector<int> v ;
} ;

}

export宣言でmodule宣言を指定すると、現在のモジュールのサブモジュールの名前を宣言したことになる。

export module module-name ;

export宣言でトップレベルの宣言をすると、その宣言は外部に公開される。


module foo

// barはfooをimportしてもimportされない
import bar ;

// fooをimportするとhogeもimportされる
export import hoge ;

// 内部
void f( int ) ;

// 外部に公開される
export void f( int, int ) ;

// 外部に公開される
export namespace foo {
    void g() ;
}

まだまだ文法は変わるだろうし、具体的な実装が出てきてからが面白いところだろう。

[読みにくいPDF] N4215: Towards Implementation and Use of memory_order_consume

memory_order_consumeの存在意義の解説。特にロックやアトミックのような命令を発行することなく、コンパイラーの一部の最適化を抑制するだけで実装可能だが、なかなかそういう高品質の実装が出てこない現状について書いている。

N4216: Out-of-Thin-Air Execution is Vacuous

虚空から現れいでたる(Out Of Thin Air)値とは、何の脈略も関連性もなく現れる値のことである。例えば、何らの排他的制御も同期処理も行わずに同じオブジェクトに複数のスレッドから値を書き込んだ場合、その結果の値は未定義となる。未定義である以上、結果の値がどのようになってもかまわない。しかしまったく脈絡のない値が出てきてもいいものか。

議論の結果、規格では実装に対しOOTAを避けるように記述されているが、具体的なOOTAについて記述されていない。この論文では、具体的なOOTAについて記述している。

N4217: std::rand replacement, revision 1

std::randを廃止したい。しかし、std::randはあまりにもお手軽に使うことができる。

1から6までの乱数をひとつ生成したいとする。大昔のrandならば、以下のように書ける。

// このようなコードを書いてはならない。
int main()
{
    std::srand( std::time( nullptr ) ) ;
    int pip = std::rand()%6 + 1 ;
}

まずstd::time()で初期化するのはお勧めできないし、剰余を使う方法は、均一に分布しない。

では、C++11ではどう書けばよいのか。

// 長い
int main()
{
    std::random_device d ;
    std::seed_seq s = { d(),d(),d(),d(),d(),d(),d(),d(),d(),d() } ;
    std::mt19937 engine( s )  ;
    
    std::uniform_int_distribution dist( 1, 6 ) ;

    int pip = dist( engine ) ;
}

このコードは毎回初期化されるし、均一に分布するが、やや長過ぎる。C++11の乱数ライブラリをまともに使うには、乱数エンジンやら乱数分布やらの概念を学ばなければならない。

std::randのような手軽さを持っていて、モダンな小さい乱数ライブラリが欲しい。そこでこの論文では、そういうライブラリを提案している。


int main()
{
    // プログラムの実行ごとに別の状態に初期化される
    std::seed_init() ;

    int pip = std:randint( 1, 6 ) ;
}

結局、手軽でなければ普及しないのであれば、入るべき提案だろう。

[PDF] N4218: Variant: a typesafe union

型安全なunionであるvariantライブラリの提案。Boost.Variantに似たインターフェースになっている。ビジターなし、Variantを再帰的に使った場合の特殊な対応なし。

int main()
{
    std::experimental::variant< int, double > v ;
    v = 0 ;
    v = 0.0 ;

    int value = std::experimental::get<double>(v) ;
}

テンプレート仮引数に指定した型のみ入れられる型安全なunionだ。

論文で言及しているが、variantは空の状態になりうるという。

variant< T, U > a = T() ;
variant< T, U > b = U() ;

a = b ; // 空になりうる

この場合、aにbを代入するために、まずaに入っているTのオブジェクトを破棄して、次にUを構築するが、Uの構築に失敗した場合は、空の状態になる。

N4219: Fixing the specification of universal-character-names (rev. 2)

universal-character-nameに対する実装の挙動の提案。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

最近、街コロというボードゲームに興味を持っているが、いまいち戦略が見いだせない。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0