2016-08-24

npm、一見無意味なパッケージを消したら1000件ものパッケージが依存するパッケージであったことが判明

npmが一見無意味に思えるfsというパッケージをSPAMとみなして削除したところ、1000件ほどのパッケージが依存するパッケージだったので、削除を取り消した。

npm, Inc. Status - "fs" unpublished and restored

今日、数分ほど、"fs"というパッケージが、ユーザーからSPAMであるという報告を受けて、レジストリから非公開にされた。これは現在復旧されている。これは私(@seldo)による人為的なミスである。私は非公開が安全であるかを確認する内部のガイドラインに従っていなかった。ビルドが阻害されたユーザーに謝罪する。

詳細:"fs"というパッケージは、無意味なパッケージである。これは単に"I am fs"をログに残して終了する。このパッケージが何らかのモジュールの依存に含まれるべき理由は一切ない。しかし、1000件ほどのパッケージが、誤って"fs"に依存している。おそらく、"fs"という組み込みのnodeモジュールを使おうとしているのだろう。この理由により、我々は同モジュールを非公開ではなく、ガイドラインに従って、deprecated扱いにした。

もし、既存のモジュールが"fs"に依存しているのであれば、安全に消すことができる。実際、消すべきである。仮に消さなかったとしても、今後も問題なく動作はする。

npmやnodejsが悪いのか、nodejs界隈のユーザー層が悪いのか判断に苦しむが、いずれにせよnode.jsはクソであることがわかる。

2016-08-23

C++17ドラフトのiostreamに入った変更点

C++17のドラフトには、現在までに、iostreamへの変更点として、以下のような変更が加えられている。

P0004R1.HTML#0: Remove Deprecated iostreams aliases

C++98の時点でdeprecated扱いだった一部のメンバーが、とうとう削除された。最初の正式なC++規格の時点ですでにdeprecated扱いだったライブラリが、ようやく削除されたことになる。

ios_baseからは、以下のメンバーが削除された。

class ios_base {
       public:
         typedef T1 io_state;
         typedef T2 open_mode;
         typedef T3 seek_dir;
         typedef implementation-defined streamoff;
         typedef implementation-defined streampos;
       };

basic_streambufからは、stosscが削除された。これは以下のように実装できる。

       template<class charT, class traits = char_traits<charT> >
       class basic_streambuf {
       public:
         void stossc() { sbumpc() ; }
       };

その効果は、ストリームの場所を一つすすめるというものだ。

他にも、実装が自明すぎて意味のないメンバー、重複するメンバーがいくつか削除された。たとえば、basic_iosからはclear。basic_streambufからはpubseekoff, pubseekpos。basic_filebuf/basic_ifstream/basic_ofstreamからはchar const *を引数に取るopenが削除された。

N3654: "quoted" proposal

iostreamにquotedマニピュレーターが入った。サンプルコードを引用すると以下の通り。

std::stringstream ss;
std::string original = "foolish me";
std::string round_trip;

ss << original;
ss >> round_trip;

std::cout << original;   // outputs: foolish me
std::cout << round_trip; // outputs: foolish

assert(original == round_trip); // assert will fire

iostreamでは空白文字で入力が区切られてしまうので、空白を含む文字列を入力した良い場合に問題になる。これに対処するために、デリミタ文字にはバックスラッシュを付与して出力し、入力にあたってはバックスラッシュを取り除く処理をする、quoted manipulatorを追加する。これにより、以下のようにかける。

std::stringstream ss;
std::string original = "foolish me";
std::string round_trip;

ss << quoted(original);
ss >> quoted(round_trip);

std::cout << original;     // outputs: foolish me
std::cout << round_trip;   // outputs: foolish me

assert(original == round_trip); // assert will not fire

ドワンゴ広告

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

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

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

公益財団法人日本生産性本部のヨーゼフ・ゲッベルスが平成28年度の新入社員のタイプは「ドローン型」であるとの報告書を発表した

世界に冠たる優れた人種であるアーリア人の中でもナチ党の国民啓蒙宣伝大臣であるパウル・ヨーゼフ・ゲッベルスは、平成28年度の極東の新入社員(極東における同年に学位を得て同時に雇用契約を結ぶ労働者の謂)は、ドローン型であるとの報告書を発表した。

公益財団法人日本生産性本部の「職業のあり方研究会」(座長 ライズコーポレーション株式会社 代表取締役 岩間 夏樹)は、平成28年度の新入社員の特徴をまとめた。「職業のあり方研究会」は、若年者の就労支援や教育の専門家などで構成され、多くの企業や学校等の就職・採用関係者の協力を得ながら、新入社員の特徴や就職・採用環境の動向などについて調査研究を行っている。

公益財団法人日本生産性本部 - 平成28年度 新入社員のタイプは「ドローン型」

ドローン型というのはよくわからない表現である。座長 ライズコーポレーション株式会社 代表取締役の岩間 夏樹なる人物がまとめたとされているが、報告書を調べてみたところ、実際に文章を執筆したのは別の人物らしい。

報告書はPDFフォーマットで公開されている。

http://activity.jpc-net.jp/detail/lrw/activity001472/attached.pdf

本当の作者名を得るために、そのPDFのinfo情報をみてみると、


$ wget http://activity.jpc-net.jp/detail/lrw/activity001472/attached.pdf
$ pdfinfo attachd.pdf
Title:          プレスリリーステンプレート
Subject:        プレスリリース虎の巻
Author:         Paul Joseph Goebbels
Creator:        Microsoft® Word 2010
Producer:       Microsoft® Word 2010
CreationDate:   Thu Mar 24 10:53:49 2016
ModDate:        Thu Mar 24 10:53:49 2016
Tagged:         yes
UserProperties: no
Suspects:       no
Form:           none
JavaScript:     no
Pages:          3
Encrypted:      no
Page size:      595.32 x 841.92 pts (A4)
Page rot:       0
File size:      814714 bytes
Optimized:      no
PDF version:    1.5

このPDFの作者はパウル・ヨーゼフ・ゲッベルスであることがわかる。奇しくもドイツ、ナチ党の国民啓蒙宣伝大臣と同姓同名である。偶然だろうか。

ヨーゼフ・ゲッベルス - Wikipedia

とはいっても、歴史上有名な方のパウル・ヨーゼフ・ゲッベルスは1945年5月1日に自殺したはずである。仮に生きていたとしても114歳になっている計算だ。

いかにプロパガンダの天才と称されるゲッベルスであっても、極東の事情はわからなかったので、やはりその報告書も精彩を欠くものと見える。

2016-08-15

C++標準化委員会の文書: P0350R0-P0359R0

[PDF] P0350R0: Integrating datapar with parallel algorithms and executors

P0214で提案されているベクトル型、dataparを並列アルゴリズムに対応させて、専用の実行ポリシーを追加する提案。そこまで明示的にする必要があるのは本末転倒な気がする。

[PDF] P0352R0: Smart References through Delegation: An Alternative to N4477's Operator Dot

operator .をオーバーロードすることによりスマートリファレンスを実装可能にしようと言うのがN4477の提案だが、operator .の現在の提案は極めてややこしい。オーバーロード解決のルールにめちゃくちゃ複雑な新ルールを導入するものだ。

この提案では、派生機能を拡張した移譲機能を追加することにより、スマートリファレンスを実装可能にしようと言うものだ。

例えば、以下のように

template < typename T >
class shared_ref : public using T
{
    std::shared_ptr<T> ptr ;
    operator T &() { return *ptr ; }

public :
    // auto x = shared_ref<T>{}のxの型はTになる
    using auto = T ;
    // sizeofの結果はsizeof(T)の結果になる。、
    using sizeof = T ; 

    explicit shared_ref( shared_ptr<T> ptr ) : ptr(ptr)
    { }

    // X::funcをhidingする。
    void func() { }
} ;

このように、既存の派生と継承の上に作ることで、すでによく知られたルールを適用できる。文法はXから派生しているようだが、shared_refのオブジェクトはXのサブオブジェクトを持たない。Xへのリファレンスは、変換関数で取得できるようにしておくことで、shared_refをXとして使いたい場合には、変換関数が使われる。

この拡張によって、スマートリファレンスを実装できるほか、pimplイディオムなども、より自然に実装できる。

これはいい提案だ。operator .のオーバーロードよりはるかに気が利いている。派生と継承のルールはすでによく知られているのでわかりやすい。

入るべきだ。

P0353R0: Unicode Encoding conversions

UTF-8/UTF-16/UTF-32の間の相互変換ライブラリの提案。現在でもC++標準ライブラリで可能ではあるが、極めてクソなライブラリしかない。

using std::literals ;
auto u8str = u8"hello,world"s ;
auto u16str = std::to_u16string( u8str ) ;
auto u32str = std::to_u32string( u8str ) ;
u8str = std::to_u8string( u32str ) ;

UTF-8文字型にはcharではなくて独自の型がほしい。

[PDF] P0354R0: default == is >, default < is < so

P0221で提案されているデフォルトの大小比較演算子に対して、デフォルトの大小比較演算子は有害だと主張する文書。

クラスに対して、デフォルトの==と!=を生成するのはわかる。しかし、<はわからない。多くのクラスは大小比較可能ではない。大小比較がデフォルトで生成されるようになった場合、筆者はコーディング規約でデフォルトでオプトアウトするように支持し、そのためにマクロを使うことも吝かではない。そのような機能はデフォルトで有効にすべきではない。

その上で、文書はデフォルトの大小比較演算子について、以下のいずれかを取るべきだとしている。

  1. 採用しない
  2. デフォルトでオプトインにして、明示的な利用宣言を必要とする
  3. std::orderingのようなカスタマイゼーションポイントを提供して、特殊化することでオプトインにする
  4. 新しい演算子を追加する

文書は、採用しないことが最も望ましく、オプトインもカスタマイゼーションポイントや新しい演算子で行われるべきだと主張している。

P0355R0: Extending to Calendars and Time Zones

にグレゴリオ暦を追加する提案

int main()
{
    using namespace std::chrono_literals ;

    auto date = 2016y/8/10 ;
    std::cout << date ;
}

まあ、ある程度便利だ。日付、曜日、タイムゾーン、うるう秒などに対応している。

P0356R0: Simplified partial function application

std::bindに変わる単純なbindの提案。

bind_frontとbind_backは、関数オブジェクトfと、任意個の実引数を取り、関数オブジェクトを呼び出す際に、実引数の先頭か末尾に受け取った引数を付け加える。

auto front = std::bind_front( f, a, b, c ) ;
front( d, e, f ) ; // f( a,b,c,d,e,f )

auto back = std::bind_back( f, a, b, c )
back( d, e, f ) ; // f( d,e,f,a,b,c) 

std::bindと違い、引数の順序変更や、引数の無視はできないが、この機能で実需要のほとんどは満たせるとしている。

個人的には、lambda式があるのでbind自体がいらないのではないかと思う。

P0357R0: 'reference_wrapper' for incomplete types

reference_wrapperを不完全型に対して使用可能にする提案。

P0358R0: Fixes for 'not_fn'

C++17に入るnot_fnの文面に問題があり、ref-qualifierを無視してしまうので、その修正をした新しい文面案の提案。

[PDF] P0359R0: SG5: Transactional Memory (TM) Meeting Minutes 2016/02/22-2016/05/23

SG5、トランザクショナルメモリーの会議の議事録

ドワンゴ広告

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

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

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

2016-08-09

C++標準化委員会の文書: P0340R0-P0349R0

P0340R0: Making std::underlying_type SFINAE-friendly

underlying_typeに対して非enum型を渡した時にクラスが定義されるように変更することで、SFINAEフレンドリーにする提案。

入るべきだ。

P0341R0: Leveraging parameter packs outside of templates

この提案は素晴らしい。

テンプレートパラメーターパックは素晴らしい。しかし、その利用はテンプレートに制限されている。実にもったいないことだ。パラメーターパックはもっと使われるべきだ。

そもそもパラメーターパックを、そのまま変数にしたい。

template < typename ... T >
struct X
{
    T ... t ;// 認められるべきだ。
} ;

template < typename ... T >
void f( T ... a )
{
    T ... fa(f(a)) ; // 認められるべきだ
}

パラメーターパックはテンプレートの外からでもアクセスできるべきだ。例えばi番目パラメーターパックの値を得るために、以下のようなコードが書けるべきだ。

template<typename ...T>
struct easy_tuple {
 template<typename U> easy_tuple(U &&u) : t{u}... {}
 T ...t;  // パラメーターパックをそれぞれデータメンバーとして持つ
};

template <int i, typename ...T> auto ith_argument(T && ...t) { /*i番目のパラメーターパックを返すコード*/ }
 
template<typename int i; typename ...T> auto get(easy_tuple<T...> tup) {
 return ith_argument<i>(tup....t& ...);  クラスの外側からパラメーターパックのデータメンバーアクセス
}

さて、これはほんの基本だ。本題は、パラメーターパックはテンプレートの外でも扱えるようになるべきだ。そのために、パックリテラルを追加する。

template<typename...T = <double, double> >
struct euclidean_space { /* ... */ };

パックリテラルがあるからには、パック値が存在する。例えば、以下のようなコードは、現在ill-formedである。

auto f()
{
    return { 2, "foo"} ;
}

{}で囲まれた式は何らかのリテラルのように見えるが、現在はそのような扱いを受けていない。パックリテラルが導入されれば、braced-init-listは第一級式として扱えるようになる。すなわち、型は<int, char const *>というパックとなる。z

パックを返すのは、pairやtupleで包んで返すより自然だ。

<double, double> calculateTargetCoordinates();
double distanceFromMe(double x, double y);
 
void launch() {
 if(distanceFromMe(calculateTargetCoordinates()...))
  getOuttaHere();
}

名前付きパックリテラル

<string topSong, person president, double avgTemp> someFactsAboutYear(int year) {
  if(year==1962)
    return {"Stranger On The Shore", Presidents.get("Kennedy"), 14};
}

パックリテラルはtupleよりも直感的な型リストを実現できる。

template<typename L, typename R> struct append;
 
template<typename ...Ls, typename ...Rs>
struct append< <Ls...>, <Rs...> > {
 using type = <Ls..., Rs...>;
};

パラメーターパックは型だけではなく非型も入れられるので、値リストも作れる。

template<typename theoretical, typename actual> struct accuracy;

template<double... predictions, double... measurements> 
struct accuracy< <predictions...>, <measurements...> >) { /* ... */ };

この提案は素晴らしい。パラメーターパックが第一級市民になる。夢が広がる。ぜひとも入るべきだ。

P0342R0: Timing barriers

パフォーマンスの計測は高速なコードを書くために重要だ。パフォーマンスを計測するには処理の前後で時間を取得して差分を得る。

int main()
{
    auto start = std::chrono::high_resolution_clock::now() ;
    do_something() ;
    auto end = std::chrono::high_resolution_clock::now() ;

    auto elasped = end - start ;
    auto millisec = std::chrono::duration_cast<std::chrono::milliseconds>( elasped ) ;

    std::cout << millisec.count() << std::endl ;
}

問題は、C++実装は規格上、as-ifルールにしたがって、処理をリオーダーできるということだ。そのため、C++実装はdo_something関数の呼び出しをstartとendの間からどこか別の場所に移しても、規格上全く問題ない。

このas-ifルールはとても強力で、現在、C++規格には移植性のある方法であるコード辺の処理時間の計測をする方法がない。mutexやスレッドの使用はリオーダーを妨げないし、分割コンパイルですら、プログラム全体の最適化やリンク時最適化の前では通用しない。

そこで、この文書では、std::timing_fenceというコードをそのブロックを超えてリオーダーしないフェンスを追加することを提案している。

確かに入るべきだ。

[PDF] P0343R0: Meta-programming High-Order Functions

メタプログラミングのためのライブラリを追加する提案。MetaとBoost.MPLとboost.Hanaを参考に設計されている。

meta::id

引数をそのまま返すメタ関数。いわゆるidentity。

meta::eval

typename T::typeをしてくれるメタ関数

Meta-Callables型

メタ呼び出し可能型は、ネストされたテンプレートエイリアスinvokeを持つ型である。Booste.MPLならばapplyに相当する。

struct identity
 {
 template <class T>
 using invoke = T;
 };

meta::invoke

meta-callablesのinvokeを呼び出すメタ関数

その他、様々なメタプログラミングを助けるためのライブラリがある。

P0345R0: Allowing any unsigned integral type as parameter type for literal operators

ユーザー定義リテラルの仮引数の型に任意のunsigned integer型を許可する。また、縮小変換を禁止する。

std::uint8_t operator "" _foo ( unsigned long long int x ) { return x ; }

// 縮小変換がかかるが、ユーザー定義リテラルの定義を見なければ縮小変換が起こることがわからない。
auto a = 1024_foo ;
// 縮小変換がかかることが明らかなので警告できる。
std::uint8_t b = 1024 ;

[PDF] P0346R0: A <random> Nomenclature Tweak

Uniform Random Number Generatorは誤解しやすい用語なのでUniform Random Bit Generatorに改名する。

P0347R0: P0347R0 Simplifying simple uses of <random> u

乱数ライブラリを使いやすくするラッパー、random_genrator<T>の提案

現在の乱数ライブラリは初心者には使いにくい。まずUniform Random Number Generatorのオブジェクトを作り、seedを初期化して、望みのdistributionクラスのオブジェクトを作り、URNGとdistributionの2つのオブジェクトを組み合わせて乱数を作る。

提案されているライブラリは、以下のように使える。

#include <random>
#include <iostream>
int main()
{
    std::mt19937_rng rng; // nondeterministically seeded, convenience typedef for std::random_generator<std::mt19937>
    std::cout << "Greetings from Office #" << rng.uniform(1,17) // uniform integer in [1, 17]
              << " (where we think PI = "  << rng.uniform(3.1,3.2) << ")\n\n" // uniform real in [3.1, 3.2)
              << "We " << rng.pick({"welcome",
                                    "look forward to synergizing with",
                                    "will resist",
                                    "are apathetic towards"})
                       << " our management overlords\n\n";

    std::cout << "On the 'business intelligence' test, we scored "
              << rng.variate(std::normal_distribution<>(70.0, 10.0))
              << "%\n";
}

mt19937_rngは、random_generator<mt19937>へのtypedefである。random_generatorは、テンプレート実引数て指定されたURNGのオブジェクトを作り、非決定的な方法でseedする。メンバー関数のuniform(a, b)に整数か浮動小数点数を渡すと、aからbまでの範囲の乱数が生成される。pickを使うと引数に渡したコンテナーの中の要素から一つが選ばれて返される。variateは非一様分布を渡すことができる。

同等のコードをrandom_generatorを使わずに書くと、以下のようになる。

#include <random>
#include <iostream>
int main()
{
    std::random_device rd; // assume unsigned int is 32 bits
    std::seed_seq sseq {rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
    std::mt19937 engine(sseq); // seeded with 256 bits of entropy from random_device

    auto strings = {"welcome",
                    "look forward to synergizing with",
                    "will resist",
                    "are apathetic towards"
                   };

    std::cout << "Greetings from Office #" << std::uniform_int_distribution<>(1,17)(engine) // uniform integer in [1, 17]
              << " (where we think PI = "  << std::uniform_real_distribution<>(3.1, 3.2)(engine) << ")\n\n" // uniform real in [3.1, 3.2)
            << "We " << *(strings.begin() + std::uniform_int_distribution<>(0, std::size(strings) - 1)(engine))
                       << " our management overlords\n\n";

    std::cout << "On the 'business intelligence' test, we scored "
              << std::normal_distribution<>(70.0, 10.0)(engine)
              << "%\n";
}

ただ、このライブラリは、uniformメンバー関数を呼び出すたびに対応するdistributionクラスのオブジェクトが作られるので、効率が悪い。このライブラリは効率と引き換えに手軽さを提供するライブラリなのでこれでいいのだとしている。

P0348R0: Validity testing issues

immediate contextによるエラーはハードエラーではないというのがSFINAEの基本となっている。では、immediate contextとは何かという問題が残っている。

この文書は、現在解釈が揺れている例をいくつか上げて、委員会はこの例に対する回答を示すべきであるとしている。

deleted定義を宣言以外の方法で参照するとill-formedであると規定されているが、別の場所では、ハードエラーにはならないと規定されている。どちらが優先されるべきなのか。ハードエラーにはならないほうがSFINAEによる利用ができて好ましい。

GCCもClangも、変数テンプレートの初期化子はimmediate contextにはならないと解釈している。

関数のデフォルト実引数の中の式はimmediate contextかどうかClangとMSVCは一貫してimmediate contextではないとするが、GCCは一貫していない。

他にもまだ問題提起はある。

[PDF] P0349R0: Assumptions about the size of datapar

P0214でdataparというベクトル型の提案をしているが、size()がコンパイル時定数になっている。しかし、世の中には可変長ベクトル型をサポートしたアーキテクチャもある。ベクトル超を可変長にするのは、将来性も見込まれている。size()をコンパイル時定数にする設計は将来の足かせになると主張する文書

ドワンゴ広告

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

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

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

2016-08-08

お気持ち表

国民、某、言さく。国民聞く、かけまくもかしこき天皇、皇位の維持につき、お気持ちを御公開遊ばされると云々。これ日本国の一大事にして、一都一道二府四十三県の貴きと賤しきとを問わず、日本国民の耳目を集むるところなり。

そもそも、天皇は日本国の象徴なり。その地位は、主権の存する日本国民の総意に基くと日本国憲法、かく言へり。天皇は国事行為のみを遊ばされ、国政に関与すること能はざるなり。これをもつてこれをみるに、天皇の皇位の進退、御意に如くに遊ばさるること能はず。就中、真の天皇の御意、公にせられること久しくなし。世にすでに発せられたる詔は、国民の総意なり。御意に非ざるなり。天皇、国政への関与を禁ぜられたるため、僅かにも国政に影響を及ぼす御意は、公にせられざるなり。

昭和天皇、千九百四十六年の一月一日に詔を発して曰く、天皇は現人神に非ずと。これをもって世は天皇は人間なりと宣言したとみなせり。畏くも天皇たりといへども、一個の人間たることはこれ明らかなり。

而して、天皇は日本国民なりや。国民某、これを知る能はざるなり。ただし、密かに思ふよう、天皇は日本国民にあらざるなり。日本国憲法より天皇は、

  1. 天皇の地位は日本国民の相違に基づく
  2. 天皇は国政に関する権能を有しない

と定義されたり。一方、日本国民は、

  • 日本国民は基本的人権を持つ
  • 日本国民は法の下に平等である。華族その他の貴族の制度は、これを認めない。
  • 日本国民はいかなる奴隷的拘束も受けない

今、試みに天皇を日本国民とす。日本国民は国政に関する機能を有する。これは天皇の定義と矛盾する。他の天皇の定義と日本国民の定義もそれぞれ矛盾するが自明のため省略。ゆえに天皇は日本国民に非ざるなり。

国民某、思ふよう、たとひ天皇は国政への参加を否定されたりといへども、一個の人間なり。人間はお気持ちを公開して可なり。お気持ちの公開は国政への関与にあらざるなり。お気持ちを国政に反映させるや否やの判断は日本国民に委ねられたり。

伏しておもんみるに、畏くもかたじけなき天皇のお気持ちを正しく流通せられること、これ重要なり。世にはびこる悪鬼外道、天皇のお気持ちをいささかの敬いの心もなくして改変すること、これ恐れあり。

ラジオは、お気持ちの流通手段として不適なり。何となれば、ラジオの発信者、お気持ちを改変する恐れこれあり。電波はいかに賎しの山賤といえども任意の周波数の発信が容易なり。

テレビは、お気持ちの流通手段として不適なり。何となれば、テレビは技術的に劣つたインターレース、技術的に劣つている上に特許汚染されたMPEG2、特許汚染されたAACを使ひ、かつ設計上の欠陥にして人道上の罪なるDRMを用ひたればなり。

天皇はお気持ちをデジタルデータに符号化するにあたって、よろしく自由なる動画符号化形式、自由なる音声符号化形式、UTF-8で符号化されたるプレインテキストを用い遊ばされたまえ。

流通は、天皇のお手元から末端の取得者までの経路がTLSで暗号化されていることが肝要なり。しかし、これとても認証局を信用せずんばあらざるなり。

幸いにして、国民某、改変を検知する算の法を知りたり。算の法の妙によりて、流通経路に不信ありとも改変の有無を検知できる神秘の法なり。

ハッシュ値は、多大なビット列を元に計算した値なり。ハッシュ値を表現するには数百ビットもあれば足る。セキュアなハッシュ関数を選択することこれ肝要なり。CRC、MD1, SHA1のごときは、既知の脆弱性があるため御避け遊ばされたまえ。天皇はよろしくSHA-2かSHA-3を御使い遊ばされるべきなり。

公開鍵暗号による電子署名は、事前に公開鍵さえ信頼できる方法で流通すれば、お気持ち発信者の秘密鍵による署名を、公開鍵所有者が検証し、お気持ちに改変がないことを検知できるものなり。天皇、よろしくGPGにて御公開鍵を御生成の上、御公開遊ばされたまえ。

国民某、思ふよう。天皇、思慮知恵、常の人にすぐと言へども、お気持ちの過ちすることこれ恐れあり。誤りは修正さるべきなり。かるがゆえに、天皇、よろしく御自らgitをお使い遊ばされて、お気持ちをバージョン管理遊ばされたまえ。

次に天皇、よろしく御自らGitHubの御アカウントを御取り遊ばされ、お気持ちレポジトリに御git push遊ばされたまえ。これにて、日本国民、もし、かたじけなくも天皇のお気持ちに誤字脱字などの誤りを発見した時は、恐れながらローカルにてお気持ちを編集させていただき、畏くもforkしたお気持ちレポジトリにgit pushしたうえで、恐れながらPull Requestなど発行させていただき、而して、天皇、かたじけなくも御自らPull Requestを叡覧あって、御マージ遊ばされたまえ。

国民某、伏して惟んみるに、天皇、御多忙につき、ハッシュ値、電子署名、中間者を介することなく配布、途中の経路をTLSで暗号化を、御自ら行い遊ばされることは煩わしからん。国民某、つらつら既存のソフトウェアを眺めるに、右のこと、電子署名以外ならば行うソフトウェアこれあり。BitTorrentプロトコルとそのクライアント、すなわちこれなり。天皇御自ら流通、ハッシュ値計算、途中の経路はTLS暗号化までは自動で行うソフトウェアなり。

国民某、また思わく、天皇、御身分を御隠し遊ばされたまま、お気持ちを御公開遊ばされたきこと、定めてこれありなん。世に、Torとて多重中継を経て匿名性を高めるソフトウェアこれあり。よろしくお使い遊ばされたまえ。

謹んで表を奉り以聞す。国民某、誠惶誠恐頓首頓首死罪死罪。

2016-08-06

アウティングは違法か?

以下のようなニュースがある。

「ゲイだ」とばらされ苦悩の末の死 学生遺族が一橋大と同級生を提訴

内容を要約するとこうだ。

同性愛者の男Aは、厳格な異性愛者の友人Bに好意を打ち明けた。Bは否定した。Bは周囲に、Aは同性愛者であることを暴露した。Aは心療内科に通院するほどの精神的苦痛を受けた。Aが籍をおく大学の相談室は、Aの相談に対して、同性愛問題を正しく把握せず、見当違いの性同一性障害を専門とする病院を紹介した。この対応にAは精神的苦痛を受けた。Aは精神的苦痛を理由として自殺した。

Aの遺族はBを訴えた。理由は、Bが周囲にAが同性愛者であることを暴露したことによる精神的苦痛は損害賠償を請求するに足るからだ。

Aの遺族は大学を訴えた。理由は、「同性愛者、うつ病、パニック発作についての知識・理解が全くなく、模擬裁判の欠席は前例がない、卒業できないかもしれない、などとプレッシャーをかけた」ことによる精神的苦痛は損害賠償を請求するに足るからだ。

Bは、「恋愛感情をうち明けられて困惑した側として、アウティングするしか逃れる方法はなく、正当な行為だった」と主張した。

大学は、「大学の対応に問題はなかった。個別の事故は防げない」と主張した。

この裁判は興味深いので、有名な判例となるはずだ。この記事では、アウティング(同性愛者であることを周囲に暴露すること)の是非について論じているが、この件は同性愛者とは切り離して考えるべきだ。というのも、

「ホモではない男がホモの男から言い寄られたので拒否したうえで、気味悪く感じ周囲に吹聴した。ホモは自殺した。」

と書けば、なるほど、ホモフォビア(ホモ恐怖症)の男による理解のない行動が悩める男を自殺に追い込んだ。悪だ。と思えるかもしれない。しかし、同性愛者という文脈から切り離すと、

「人Aは人Bから言い寄られたので拒否したうえで、気味悪く感じ周囲に吹聴した。Aは自殺した。」

となる。では、ここに別の文脈をつけてみよう。

「20代の若くて美人な女子大生が、40代でハゲでデブでキモいオッサンに言い寄られたので拒否したうえで、気味悪く感じ周囲に吹聴した。オッサンは自殺した。」

これはどうだろうか。当然の結果だろうか。それとも、ルッキズム(Lookism、人を見た目の良し悪しで判断する美貌主義)とジェロントフォビア(Gerontophobia、加齢恐怖症)の女による理解のない行動が悩める男を自殺に追い込んだ。悪だ。と思うだろうか。

文脈を取っ払うと、どちらもやっていることは同じだ。そして、現実を見ると、同性愛者の男性カップルと同じ程度には、40代の男と20代の女の年齢差カップルは存在するのではないか。もしそうであるならば、後者と前者は同じ程度に起こりうる問題であり、当然同じ判断が適用されるべきである。残念ながら、具体的な統計が見つからないので、カップルの比率は感覚でしかないのだが。

言い寄られた立場から考えると、どちらも言い寄られたことに対して不快感を持ったとしてもおかしくはない。厳格な異性愛者が同性愛者から言い寄られたら不快感を持つであろうし、20代の若い女性が40代の性的魅力のない男から言い寄られるのも不快感を持つだろう。その不快感の解消方法として、周囲に相談をすることは悪であろうか。

と考えていくと、私はこの問題の善悪を判断できかねる。納得の行く説明付きの判決が出て欲しいのだが、おそらくどちらに転ぼうとも私の常識では納得できないだろう。

大学に関しては、私は責任がないと考える。というのも、私は「無知が罪」となることはおかしいと考えているからだ。大学の相談室に同性愛に対する高度な医療知識がなかったために、間違った診療科を紹介したことは罪ではない。また、クラス替えや留学の希望に対する対応でも、同性愛が絡まない他の事例と代わりがないのであれば、特別に差別されていたとは言えない。それに、大学は学生の私的な生活に踏み入るべきではない。

Bjarne Stroustrupのプログラミング入門書の査読の感想

アスキードワンゴ編集部からBjarne StroustrupのProgramming -- Principles and Practice Using C++という本の第二版の邦訳が出版される。初版は翔泳社が出していたが、C++14に対応した改訂版の第二版の版権が空いていたので、アスキードワンゴから出すための作業をしていた。私は邦訳の査読をした。

今年になってから半年は、ずっとこの本の査読をしていた。このためにC++標準化委員会の最新の文書を把握する作業が数ヶ月ほど滞った。そして、この仕事は、私がドワンゴに入社して以来、最悪の仕事であった。ただし学びはあった。それについて書いていこうと思う。

Bjarne Stroustrupは、ご存知の通りC++の最初の設計者にして最初の実装者である。現在、Texas A&M Universityで教鞭をとっている。この本はStroustrupの講義のための教科書として書かれた。対象読者は、入学して最初のセメスターで初めてプログラミングを学ぶ学生である。

結論から言うと、この本は極めて悪く書かれている。およそ悪書の見本のような本だ。悪文の集大成といってもよい。プログラミング言語入門用としても悪い。

先に、この本の査読の仕事は、私がドワンゴに入って以来最悪の仕事だと書いたのは、この本が極めて読みづらく不必要に難解で、しかもその内容が噴飯物の間違いだらけであったからだ。学びがあったというのは、この悪書の見本を網羅している本を査読することで、「いかに本を書いてはいけないか」について実感できたからだ。かのLinus Torvaldsは言った(どこかで読んだ記憶があるのだが、出典が見当たらない)

「迷いが生じた時は、Subversionの逆をやることにした」

-- Linus Torvalds、gitを開発することにおいて

今回、この本の査読という貴重な体験ができたことで、今後私がプログラミングの参考書を執筆するときは、反面教師として逆張りを行うようにする。

さて、ここからは、Stroustrupのプログラミング入門がいかに悪書であるかを、具体的に書いていく。

本の文章量が多すぎる。

Stroustrupのプログラミング入門第二版の原書は1312ページある。邦訳も同じ程度のページ数がある。本書の担当の編集者は、「僕が担当した本のなかでも最大の記録を更新しましたね」と言った。私はこの本を鈍器と呼んでいる。理由は、人が殴り殺せるほどの重さがあるからだ。

これが、Stroustrupのプログラミング言語C++のような本であれば、どれだけ文章量が多かろうと問題はない。そういう本だからだ。しかし、これは初心者への入門書である。

本書の翻訳は、第一版と同じ翻訳者が新たに行った。翻訳の質は、概ね原書に忠実だ。一部変な翻訳を発見したし、まだ未発見の問題もあるだろうが、これだけの文章を翻訳したにしては、かなり一貫している翻訳だ。

問題は翻訳ではなく原文(英語)にあるというのも原文は極めて読みづらく関係詞(thatとかwhichとか)や接続詞(andとかorとかyetとか)で文章を遠慮無く一文一文を長大にしている上に括弧の多用(こういうやつ)で更に文章の長さを水増ししているからであって決して翻訳の質が低いからではなく概ね原文に責任がある。

文章はしばしば話が脱線する。「Aをするのは良い作法であるとされている」、「Bは悪い作法であるとされている」などの妥当ではあるが冗長な話への脱線がよくある。

そして中でもひどいのは、わざと間違ったソースコードを提示したうえで、「これが私たちの考えた最初の解法だ。しかしこれは動かない。なぜだろうか考えてみよう。一見すると動くように見える。何が間違っているのだろうか。ひょっとしてAだろうか。いや違う。Bだろうか。そうでもない。実は・・・」といった自問自答の文章が延々と続くものだ。

この本は、筆者と読者をひっくるめて「私たち」と表現している。これはこの本の独特の表記法であり、わざわざ、「なぜ私たちは私たちという表記を採用するに至ったか」という説明まで書いてある。

xkcd: Manuals

そこまで書いている以上、翻訳でも「私たち」という表現を維持しなければならないのは当然の話だ。実際維持しているが、極めて日本語として不自然な文章になっている。

このことから、私たちはとても重大な教訓を得た。

教訓1: 文章は簡潔にすべし

人間が読める文の量と速度は有限である。重要なのはプログラミングの仕方を教育することであって、文章の量ではない。

これは文が悪文だったというものだ。次は技術的な悪書の理由について書く。

サンプルコードの1割ほどがコンパイルできない

コンパイルできない理由は、識別子が間違っているとか、あるべき記号が欠けているとか、極めて些細でお粗末なtypoがほとんどだ。

このような問題は、本のソースコードからサンプルコードを抜き出してコンパイラーに通して文法違反がないかどうか確かめるテストを書けば防げる話だ。そして、この本はわざわざ大量の文章を割いて、テストの重要性を説いている。Stroustrupには、「医者の不養生」というニッポンのコトワザを教えてあげたい。

この本は、はじめC++11向けに、おそらく2006年か2007年ごろから書かれたものが、2008年に出版され、それをC++14に対応させ、また C++11の規格制定後に、C++11の新機能を使った行儀の良いお作法に対応させる修正を行っている。

その過程で、「ふふん、この程度の変更は自明だからコンパイルして確認するまでもないね」という怠惰とうぬぼれがあったのだろう。テストを書くべきである。

Stroustrupであろうと混乱したであろう興味深い間違いの例はある。例えば、変数の初期化をbrace-or-equal-initializerにすることでnarrowing conversionを防ぐなどのお作法のために、サンプルコードを全面的に修正したりしている。

void f( int x )
{
    short s1 = x ; // OK、ただし縮小変換
    short s2{x} ; // エラー、縮小変換は禁止されている
} 

問題は、これを以下のようなstd::string s(1, 'a')というコードに対して盲目的に適用してしまったことだ。

// "a"で初期化
std::string s1(1, 'a') ;
// "\x01a"で初期化
std::string s1{1, 'a'} ;

理由は、brace-or-equal-initializerでは、まずstd::initializer_list<T>を引数に取るコンストラクターが探され、ない場合は、その他のコンストラクターで引数の数と型があるものが探される。std::stringには、initializer_list<char>を引数に取るコンストラクターがあるので、そちらが優先される。

そして、リスト初期化のnarrowing conversionの禁止は、コンパイル時定数で変換先の表現可能な範囲である場合は発生しない(より正確には、そのような場合はnarrowing conversionとみなされない)。その結果、{'\x01', 'a'}というリスト初期化だと解釈されてしまった。

これはコンパイルも正常に通ってしまうので、実行して出力を確認しない限り見抜けないバグだ。

もうひとつの例は、C++03とC++11で挙動が変わるコードだ。

bool can_open(const string& s)
// check if a file named s exists and can be opened for reading
{
     ifstream ff(s);
     return ff;
}

can_open関数は、引数として与えられたファイル名でファイルを開けるかどうかを確認する関数だ。問題は、ffがファイルを開いているかどうかを、boolへの暗黙の型変換で調べている。ifstreamはbasic_iosから派生していて、basic_iosはoperator void *()という変換関数を持っていて、ファイルが開いているかどうかをnullptrかどうかで返すのだが、これは問題が多いとして、library issue 468ではexplicit operator bool()に変更された。そのため、C++11ではコンパイルエラーになる。

そもそも、暗黙の型変換に頼るのが間違いなのだ。ファイルを開いているかどうか確認するメンバー関数is_open()があるのだから、それを使えばよい。

これは、コンパイルさえしていれば発見できた問題だ。

全体的には、極めてお粗末で些細なill-formedなサンプルコードばかりだ。

教訓2: テストは重要だ

著者の文字コードへの理解がない

本にはこう書いてある。

「テキストファイルの最初の4バイトは4文字である」

この文脈は、テキストファイル一般の話だ。これから扱う課題の入力に使うテキストファイルの最初の4バイトは常に4文字であるとみなすという仮定の話ではない。つまり、1文字は1バイトであると書いていることになる。

このような内容のプログラミングの参考書を日本で出版したならば、マサカリが雨となって降り注ぎ、著者、編集者、査読者は二度と顔を出して表を歩けず、出版社の信頼は地に落ちることうけ合いだ。そして、すでにC++11にはUTF-8/UTF-16/UTF-32文字列リテラルが入っているのだからなおさら悪い。この文章は到底受け入れがたい。

そして、この本には、「中国の文字やマラヤーラム文字をサポートするには」などという文章も入っている。中国の文字やマラヤーラム文字をサポートした現実の文字コードは、すべて可変長エンコードであり、1文字は1バイトとは限らない。

また、中国の文字やマラヤーラム文字をサポートするには、というのに続けて、C++の標準ライブラリのiostreamやlocaleの詳細な参考書を読むべきだとも書いている。iostreamやlocaleは、設計上可変長エンコードに対応できず、この文書は無責任である。

またひどいことに、C++11で入った正規表現ライブラリもUnicodeに対応していると書いている。実際は対応していない。そもそも、可変上文字列に対応できない設計になっている。受け入れがたく無責任にもほどがある。

筆者はこれを何度もBjarne Stroustrupに指摘したが、残念ながら話が噛み合わず、本人に修正を促すことはできなかった。曰く、「これは英語圏の話であるから」。しかし、もはや英語圏とてUnicodeから逃れることはできないというのに。

そして、筆者の使う、unacceptableとかirresponsibleという言葉を侮辱的であると返すばかり。侮辱的にしろ、unacceptableなものはunacceptableであり、irresponsibleなものはirresponsibleでしかない。

このため、該当箇所に間違っていると指摘する注釈を入れ、また原文にない章を特別に追加して、現実の文字コードと、C++の文字と文字列とライブラリ、C++の規格と現実の文字コードの対応、Apple, GNU/Linux, Windowsにおける文字コードの取り扱いなど、日本人プログラマーなら誰でも知っているし、Wikipediaなどで簡単に調べられることを、簡単に浅く説明した。筆者の専門ではない分野を扱ったのでマサカリが山と飛んでくることを恐れている。

Cプリプロセッサー

この本のサンプルコードは、すべてstd_lib_facilities.hというヘッダーファイルを#includeすることが前提で書かれている。このヘッダーの中身は、本で使っている標準ライブラリヘッダーの#includeや、有益ないくつかの関数の追加。またusing namespace std ;などが書かれている。グローバル名前空間に読み込まれるヘッダーファイルでusing namespace std;を書くのはよろしくないが、これが入門書だということを考えると、まだ納得もできる。

ただし、納得のできないことはある。これだ。

#define vector Vector

Cプリプロセッサーで、vectorというトークンをVectorに置き換えている。Vectorとは何か。以下のように定義されている。

template< class T> struct Vector : public std::vector<T> {
 using size_type = typename std::vector<T>::size_type;


 using std::vector<T>::vector; // inheriting constructor

 T& operator[](unsigned int i) // rather than return at(i);
 {
  if (i<0||this->size()<=i) throw Range_error(i);
  return std::vector<T>::operator[](i);
 }
 const T& operator[](unsigned int i) const
 {
  if (i<0||this->size()<=i) throw Range_error(i);
  return std::vector<T>::operator[](i);
 }
};

ようするに、operator[]でもat()を使った範囲外チェックを行うようにするものだ。

本では、これを必要悪であり、現実のソフトウェアプロジェクトでもこのような技法を使うことはあり、実際に役に立っていると書いているが、とんでもないことだ。

範囲外チェックを行いたければ、最初からat()を使っておけばいいのだ。fstreamを暗黙の型変換でboolに変換してファイルがオープンされているかどうか調べようとしたり、Stroustrupは大昔の粗野な時代の悪い癖が抜けていないのではないかと疑う。

課題の設定

この本では、まず冒頭で変数や関数、式、文など言語の文法の基本を教えたあと、次の章で練習課題を出している。この本は、まだプログラミング経験の一切ない初心者を対象にしていることを思い出してほしい。その上で、いま変数や関数やif文を覚えたばかりの初心者が、以下の課題を解く難易度を考えてほしい。

「実数と四則演算と括弧がある数式を標準入力から読み込んで計算結果を標準出力する計算機を実装せよ」

実数と四則演算までならまだ初心者でもなんとかなるだろうが、括弧が出てきた時点で完全に初心者向けではない。

この本では、まずBNF記法で数式の文法を定義したあと、教科書的な再帰下降構文解析による数式のパーサーを書いて計算を行っている。SICPでも冒頭でここまで無茶な課題はなかったはずだ。

もちろん、面白い課題であり、全プログラマーがプログラミング学習の比較的早い段階で一度は練習のために実装してみるべき課題ではあるが、いかにもタイミングが早すぎる。

Bjarne Stroustrupの本がここまで悪書だとは思わなかった。特に文字コードへの理解が致命的にない。

Stroustrupのプログラミング入門の査読の仕事で、筆者は反面教師としての貴重な教訓を得た。また、C++11/14コア言語の執筆の経験からも、いろいろと執筆環境の不満点はあった。そこで、筆者が次に参考書を執筆するときは、以下のような環境で行おうと考えている。

  • OSにUbuntu GNU/Linuxを使う。理由は、必要なソフトウェアが標準のパッケージマネージャーで揃う上、C++を書く上で圧倒的に快適だからだ。
  • テキストディターにVimを使う。
  • 執筆環境はgitで管理する。

  • GNU Makeで参考書のビルドとテストを管理する。これ以上に複雑なビルドシステムは、参考書執筆では必要がないと判断した。
  • 参考書のソースコードはMarkdownで書く。
  • HTMLなどの各種フォーマットへのコンパイルはpandocを使う。
  • HTMLへの出力では、数式はmathjaxを使う。ただし、KaTexも興味深いので評価中だ。
  • HTMLへの出力では、ソースコードはhighlight.jsを使ってシンタックスハイライトする。
  • 参考書のソースコードからサンプルコードを抽出してGCCとClangで文法チェックをする。
  • textlintで日本語のチェックをする。できるだけ簡潔な文章を維持するために文章にこういったツールで制約をかける。

すでに、これらのことをだいたい実装している。まだC++17の参考書を書くには不確定要素が多すぎるが、そろそろ準備は始めるべきだ。

一つ不満なのが、textlintの実装がnode.jsで書かれていることだ。もちろん、ツールとして使うのであるから、正しく動作さえすれば、どのような言語で書かれていようと気にしないのだが、結果的に、textlintの導入方法がなかなか厄介だった。Ubuntuにはnodejsパッケージがあるが、これはJavaScriptの実行環境が/usr/bin/nodejsというファイル名になっている。理由はすでにnodeというファイル名のパッケージが存在していて、名前が衝突するからだ。nodeパッケージをいれないのであれば、nodejs-legacyパッケージを入れることによって、/usr/bin/nodeへのsymlinkを貼れる。そして、GitHubのレポジトリから直接/usr/localにファイルを引っ張ってくる。npmにより、パッケージ間の存関係が極めて複雑で、とても些細な機能ですらパッケージ化されている。

ドワンゴ広告

ドワンゴは1文字は1バイトではないとわかっている本物のC++プログラマーを募集しています。

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

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

2016-08-02

C++標準化委員会の文書: P0330R0-P0339R0

[PDF] P0330R0: User-Defined Literals for size_t

std::size_t型を返すuser defined literal suffixのzuを追加する提案。これにより、size_t型の変数をautoで宣言できるようになる。

using namespace std::support_literals;
auto size = 123zu ;

サフィックスのない整数リテラルの型はint型になるため、これまでズボラなプログラマーは符号付き整数をstd::size_t型の変数に代入したり比較したりしていた。符号付き整数と符号なし整数を変換したり比較すると、思いがけぬ挙動につながるので、好ましくない。

P0331R0: P0331r0 : Motivation and Examples for Multidimensional Array

多次元配列array_refの動機と利用例

P0332R0: P0332r0 : Relaxed Incomplete Multidimensional Array Type Declaration

array_refは、配列型を渡すことによって、一部を動的なサイズにすることができる。

array_ref< int [][5][] > a ;

これを実現するために、配列の宣言の文法を変更する。

P0333R0: P0333r0 : Improving Parallel Algorithm Exception Handling

Parallelism TSで並列ベクトル実行ポリシーでアルゴリズムを実行した時に、要素アクセス関数が例外を投げた場合、直ちにstd::terminateが呼ばれる。これは他の実行ポリシーのexception_listを投げる挙動と違い、一貫性がない。そこで、並列ベクトルポリシーの場合でもexception_listを投げるようにする。また、並列ベクトル実行ポリシーはbad_allocも投げることがある。

P0334R0: P0334r0 : Immutable Persistent Containers

変更できないコンテナー、immutable_listの提案。

immutable_listは要素を変更出来ないコンテナーだ。「変更」したいときは、新しいimmutable_listのオブジェクトを作る。要素は参照カウンターで管理されている。

確かに、標準ライブラリにほしいコンテナーだ。Haskellが参考にされている。

[PDF] P0335R0: Context Tokens for Parallel Algorithms

並列アルゴリズムにコンテキストトークンを追加する。

parallel::for_each( vec, 0, N, []( auto i )
    {
        parallel::for_each( par, 0, N, func ) ;
    } ) ;

このように、並列アルゴリズムがネストする場合で、外側の実行ポリシーがベクトルで、内側の実行ポリシーが並列の場合、挙動は未定義になる。この誤りを検出する方法がない。

そこで、要素アクセス関数(この場合、lambda式やfunc)にコンテキストトークンを与え、同トークン経由で並列アルゴリズムを呼び出す方法を付け加える。

parallel::for_each( vec, 0, N, []( auto context, auto i )
    {
        context.for_each( par, 0, N, func ) ;
    } ) ;

これにより、実行ポリシーの伝播が正しく行われるようになる。

[PDF] P0336R1:Better Names for Parallel Execution Policies in C++17

並列アルゴリズムの実行ポリシーの名前をリファクタリングする提案。シングルトンオブジェクトのseq, par, vecは変わらないが、std::execution名前空間の下におかれるようになる。

P0337R0: P0337r0 | Delete operator= for polymorphic_allocator

polymorphic_allocatorからoperator =を削除する提案。

polymorphic_allocatorはステイトフルなアロケーターである。propagate_on_container_copy_assignment と propagate_on_container_move_assignmentはfalseを返す。これは意図的なものである。理由は。ステイトフルなアロケーターは一度コンテナーに入れたら、そこから動かすべきではないからだ。その設計思想から考えれば、そもそもoperator =を提供すべきではない。operator =を使って失敗する例がいくつもある。そこで、operator =を削除する。

[PDF] P0338R0: C++ generic factories

汎用的なfactory関数の提案。

C++には、いわゆるmake系のfactory関数が存在する。例えば、make_sharedとかmake_uniqueとかmake_pairなどだ。

make関数が作られる理由は主に2つある。

新しく型を作るfactory関数

back_inserter、make_optional、make_ready_future, make_expectedなど、新たに型を作り、そのオブジェクトを返すものがある。

emplace構築を行うもの

make_uniqueやmake_sharedなど。

また、make_pairやmake_tupleのような、新たに型を作り、かつemplace構築まで行うものがある。

この提案は、そのような様々なmake_foobar関数を、make関数に統一しようと言う提案だ。例えば以下のようなードが、

int v=0;
auto x1 = make_shared<int>(v);
auto x2 = make_unique<int>(v);
auto x3 = make_optional(v);
auto x4v = make_ready_future();
auto x4 = make_ready_future(v);
auto x5v = make_ready_future().share();
auto x5 = make_ready_future(v).share();
auto x6v = make_expected();
auto x6 = make_expected(v);
auto x7 = make_pair(v, v);
auto x8 = make_tuple(v, v, 1u);
future<int&> x4r = make_ready_future(std::ref(v));
auto x1 = make_shared<A>(v, v);
auto x2 = make_unique<A>(v, v);
auto x3 = make_optional<A>(v,v);
auto x4 = make_ready_future<A>(v,v);
auto x5 = make>(v, v);
auto x6 = make_expected<A>(v, v);

以下のように書ける。

int v=0;
auto x1 = make<shared_ptr>(v);
auto x2 = make<unique_ptr>(v);
auto x3 = make<optional>(v);
auto x4v = make<future>();
auto x4 = make<future>(v);
auto x5v = make<shared_future>();
auto x5 = make<shared_future>(v);
auto x6v = make<expected>();
auto x6 = make<expected>(v);
auto x7 = make<pair>(v, v);
auto x8 = make<tuple>(v, v, 1u);
future<int&> x4r = make<future>(std::ref(v));
auto x1 = make<shared_ptr<A>>(v, v);
auto x2 = make<unique_ptr<A>>(v, v);
auto x3 = make<optional<A>>(v,v);
auto x4 = make<future<A>>(v,v);
auto x5 = make<shared_future<A>>(v, v);
auto x6 = make<expected<A>>(v, v);

make関数にテンプレート名を渡すと、それぞれに対応したfactory関数として振る舞う。

テンプレート名ではなく、型を渡すことも可能である。これによって具体的に指定することも可能になる。

auto x = std::make< unique_ptr<long>>(0) ;

P0091によって、コンストラクターからテンプレート実引数の推定ができるようになるので、make関数の一部の機能は普通に書けるようになるが、それでもmake関数の優位な点はいろいろあると主張している。

customization pointとしては、std::factory_traits<T>が提供されている。これを特殊化することによってユーザー定義のクラスに対する挙動を追加できる。

[PDF] P0339R0: polymorphic_allocator<void> as a vocabulary type

polymorphic_allocator<void>を、型を指定せずに使えるあロケーターにしようと言う提案。

ドワンゴ広告

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

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

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

2016-07-29

東京都知事選挙の候補者の主張の実現可能性の考察

現在、都知事選挙が行われている[要出典]。筆者の手元には、東京都選挙管理委員会の発行した、「東京都知事選挙 選挙公報」と題された新聞様の文書がある。この選挙公報は、「立候補者21名のうち掲載申請があった20名から提出された原稿をそのまま製版の上掲載」しているという。

この選挙公報をつらつら眺めていると、多くの立候補者の主張する公約の実現には、極めて超法規的な権力(既存の国際条約、憲法、法律、条例への違反)、日本の単年度国家予算(一般会計と特別会計を合わせて重複を省いた額、だいたい200兆円ほど)を超える金、時には物理法則を捻じ曲げる必要があることに気がついた。

しかし、それでもなお、公約を真面目に実現させた場合の状況を想像すると、なかなかにユーモラスな結果となることが予想される。そこで、この記事では、今回の都知事選挙の立候補者が選挙公報に寄せた内容を公約とみなし、文字通り実現させることが可能か、そして文字通り実現させた場合に起こるユーモラスな結果を考察したい。

今回の考察にあたっては、通常の常識における制約は考慮しない。都知事には超法規的な権力が与えられ、都知事の意思ひとつで、すべての日本国が批准する国際条約からは脱退できるものとし、日本の憲法、法律、条例は変更可能とする。すべての日本国民は、さながら大躍進政策や文化大革命のごとく、都知事の計画経済にしたがって行動するものとする。あらゆる倫理、道徳より都知事の意思が優先するものとする。

ただし、最低限の制約は必要である。そこで、物理法則に違反する内容(例:永久機関)は不可能とする。また、日本の単年度国家予算(約200兆円)を超える金が必要な内容は条件付き実現可能とする。日本国外に対する内容には通常の常識を適用する。

考察する立候補者の順番は、選挙公報の順番であり、他意はない。

立花考志

この立候補者の公約は全て実現可能である。

この立候補者の主張は、東京都の条例によってMHK集金人の戸別訪問を規制するとか、放送法の改正によってNHKの受信料を支払わなくてもよくするといったたぐいのことである。今回の考察における大胆な制約の下では、NHK自体を消失させることも可能であるので、この程度のことは、他の立候補者の主張に比べれば、比較的簡単に実現可能である。

マック赤坂

この立候補者の公約は条件付き実現可能である。実現可能性は、現在の条件に依存する。

この立候補者の公約の多くは、金さえあれば実現可能である。例えば、「待機児童ゼロ、老人介護施設3倍増」とか、「中学生以下65才以上に3万円支給」とか、「東京全域バリアフリー化」などといった公約は、日本の国家予算の範囲内の金で実現できる。

また、抗うつ薬の使用禁止とか精神科医の免許取り消しなどといった公約も、法律を改正すれば容易に可能である。

「東京オリンピックを大成功させる」という公約には、日本国外の人間の動員も必要であるが、オリンピックは世界的に有名なイベントであるから、日本国内さえ十分に整備して全国民を強制徴用して動員すれば大成功は可能であろう。

ただし、疑問点はある。

「都職員に・・・能力給・信賞必罰を徹底し人員の20%カットを目指す」という内容は、論理的に成り立たない可能性がある。現在の都職員の20%以上が本来不要であるならば可能である。しかし、もし不要な都職員が20%未満であれば、彼は不要でもないのに不当に解雇される。これは信賞必罰と矛盾する。したがって、この立候補者の公約が実現可能かどうかは、現在の都職員の20%以上が不要であるかどうかにかかっている。

「スマイルあふれる東京」を実現するには、東京にいる人間に強力な抗うつ剤、あるいは筋弛緩剤(顔面を弛緩させることにより笑っているような表情にする)の摂取を義務付けるなどして、強制的にスマイルを発生させなければならない。公約では同時に抗うつ剤の禁止を主張しているので、例えば亜酸化窒素のような顔面の筋肉を弛緩させる薬品を使うのであろう。極めてディストピアな世界になるが、もちろん実現可能だ。

また、「都内のレストランにチップ制を導入」とある。日本ではチップの文化がないので、これを導入するには大躍進や文化大革命のごとき都民の強制徴用と動員が必要になる。

総合的に判断して、この立候補者の公約は、疑問点がいくつかありながらも、実現可能である。

鳥越俊太郎

この立候補者の公約は実現不可能である。

この立候補者の公約の多くは、金さえあれば実現可能である。必要な金は国家予算を超えないので実現可能である。

がん検診の促進や骨粗しょう症対策は、通常の常識の範囲内でも実現可能であるし、災害に強い東京も、金さえあれば実現可能である。

ただし疑問点はある。「希望するすべての人が正社員になれる格差のない社会をつくり」とあるが、これは難しい。ここでいう「正社員」とは労働基準法等に基づく被雇用者であって、かつ、有期契約労働者や派遣労働者や請負ではなく、仕事を依頼する人間が直接、期間を限定せず、雇用するものをいうのであろう。

これは、雇用された会社ではなく、常に客先に常駐している派遣をなくすのであれば、通常の常識の範囲内ではあるが、「希望するすべての人」という条件により、通常の常識からは外れてしまう。

例えば、筆者の自宅の壁付けコンセントが破損したとする。コンセントの修理には電気工事士の資格が必要である。筆者は同資格を保有していないので、資格保有者に修理を依頼する。もし、資格保有者が正社員を希望した場合、筆者は資格保有者を雇用しなければならない。もちろん、有期雇用契約ではなく無期雇用契約でなければならない。

これを実現するには、人を雇用する手間を極端に下げなければならない。例えば、役所に印鑑証明でも出しに行く程度の気軽さで、雇用契約を結べるよう、行政の手厚いサポートが必要だ。雇用の概念も大幅に変わるだろう。この公約が実現した社会では、都民ひとりひとりが大勢の人間を相互に雇用しあっている状態になる。もはや現在の「正社員」などどうでも良くなっているはずだ。しかし、実現可能ではある。

「職人を大切にするマイスター制度を拡充します」と書いてある。「拡充」とは大辞林 第三版の解説によれば、「設備・組織などをひろげ,充実させること」である。すると、都知事選前にすでに日本にマイスター制度が存在しなければならない。現在、日本にはマイスター制度は存在していないので、この公約は前提となる条件を欠き実現不可能である。

「できるだけコンパクトでシンプルな2020オリンピック」と書いてある。オリンピックは大規模なイベントであり、コンパクトではないので実現不可能である。今回の考察では、多額の金を費やすことにより実現可能なことは実現可能だと判定するが、実現には多額の金がかかるにもかかわらず金をかけずに実現するという矛盾した公約は実現不可能だと判定する。

増田ひろや

この立候補者の公約はすべて実現可能である。

この立候補者の公約の多くは、金さえあれば実現可能である。必要な金は国家予算を超えないので実現可能である。

例えば、子育てや介護福祉や女性の活躍の場の充実などは、金があれば実現可能である。災害対策として上げている木造住宅の不燃化、耐震化も、金があれば実現可能である。オリンピックの成功や、その後も成長を続けるなども、金があれば実現可能である。

ただし疑問点がある。

「都民が、あたたかさにあふれ、不安がなく、安心して生活できる環境・社会の実現を目指します」とある。

「あたたかさにあふれ」るためには、暖房を完備しなければならない。冬の屋外でも「あたたかさにあふれ」るためには、屋外に隙間なく暖房器具を配置するか、すべて屋内にしてしまう必要がある。すべてを屋内にした場合、東京都民はドーム型通路の中を歩いて移動することになる。これは、金さえあれば可能だ。

「不安がなく」なるためには、全都民に強力な抗うつ剤の摂取を義務付けなければならない。極めてディストピアな世界となるが、もちろん実現可能だ。

桜井誠

この立候補者の公約は実現不可能である。

この立候補者の公約の多くは、倫理、道徳さえ無視すれば実現可能である。

倫理上問題のある外国人生活保護の廃止、表現の自由を侵害する半日ヘイトスピーチ禁止条例制定などは、今回の考察の制約の範囲内で実現可能である。

実現不可能なのは、「コンパクトな東京五輪の実施」だ。オリンピックは大規模なイベントでありコンパクトではないので実現不可能である。今回の考察では、多額の金を費やすことにより実現可能なことは実現可能だと判定するが、実現には多額の金がかかるにもかかわらず金をかけずに実現するという矛盾した公約は実現不可能だと判定する。

今尾貞夫

この立候補者の公約はすべて実現可能である。

この立候補者の公約の多くは、金さえあれば実現可能である。

子育て、教育にかかる個人負担はないとか、幼稚園、保育園は誕生直後から全員受け入れ態勢を取るとか、老人介護のために食堂浴場を整備した家を作るなどは、国家予算以下の額の金で実現可能である。

実現可能ではあるが疑問のあるものとして、直接民主制の導入を主張していることだ。

「知事交代をチャンスに都民皆の希望を集約、生活不安解消策を皆で見出し、皆で実現していく皆の参加する都政に変えます。」

皆が参加する都政を実現するためには、選挙で代表者を選出するのではなく、都民皆が議会に参加できる必要がある。したがって、この公約を実現するには直接民主制に切り替える必要がある。

谷山ゆうじろう

この立候補者の公約は条件付き実現可能である。実現可能性は、国外の未来の条件に依存する。

この立候補者の公約の多くは、実現可能である。

ただし、国外の未来の条件に依存した公約がある。

「「DONALD TRUMP アメリカ大統領」に毅然とNO」と書いてある。2016年アメリカ合衆国大統領選挙において、ドナルド・トランプは立候補者の一人であり、大統領になる可能性があるが、大統領選挙は2016年11月8日に行われ、投票結果が正式に発表されるのは2017年1月とされている。したがって、ドナルド・トランプが今回、あるいは将来のアメリカ合衆国の大統領になるかはまだ未定であり、もしドナルド・トランプが大統領にならなかった場合、大統領ではないので、前提となる条件を欠き、「毅然とNO」と言うこともできない。

今回は選挙公報の実現可能性だけを考察するものであって、その内容の良し悪しについて考察はしない。しかし、この立候補者の選挙公報の日本語は、解釈が難しい。例えば、以下は選挙公報からの抜粋である。

2020年世界はTOKYOに

その中心地、国立競技場からのみ発信します

イギリスBBC、中東アルジャジーラTVなど世界を舞台に活動してきた谷山ゆうじろう
は、毎日英語で定例記者会見を行いNHKワールドで生中継。日本を売り込みます

TOKYOから国際化&自立国家

国際人を育む、夢のあるカラーフルなシティTOKYOを目指す

既成政党の組織票・お金ありきの選挙戦に、断固反対します。名前を連呼するだけの選挙カーなし、
事務所なし、ガソリン代なし。あるのは国家観と、iPhoneのみ。従来の思考回路ではもう日本は
進化できません。毎年2万人人口減少の高齢化の中で、若い人に夢を。移動中のスマホで、ご家庭
のPCで、2020東京オリンピックスタジアム(建設中)前からの生放送演説をぜひお聞きください。

これは一部だが、とにかく文章らしい文章がない。「iPHoneのみ。」とか、「若い人に夢を。」とか、よくわからない文章の区切り方と構成をしている。筆者の解釈によれば、この立候補者は、

  • 2020年に国立競技場から発信(生放送演説?)をする
  • 発信は国立競技場からしか行わない
  • 東京オリンピックスタジアムでも生放送演説(発信ではない?)を行う
  • 演説の際、東京オリンピックスタジアムはまだ建設中である(生放送演説は2020年ではない?)
  • 事務所もガソリン代もない

などの情報が得られたが、この日本語の解釈が正しいのかどうか、筆者には自信がない。発信と生放送演説は違うことと、生放送演説は2020年ではなさそうなので、記述は矛盾しないように読める。この立候補者の文章の日本語は極めて解釈が難しいため、今回の実現可能性の考察は完全に間違っている解釈に対して行っている可能性がある。

後藤輝樹

この立候補者の公約は条件付き実現可能である。公約は国家予算を超える金があれば実現可能である。

この立候補者の選挙公報は、ほとんどが公約の箇条書きで構成されている。立候補者の学歴や職歴、属する政党などの公約ではない情報は極めて少ない。

この立候補者の公約をすべて実現するには、日本の国家予算を超える金が必要になる。したがって、この立候補者の公約は条件付き実現可能と判断した。

特に金のかかる公約は以下の通り

「すべての低所得者(国民)に毎月8万円支給します(ベーシックインカム導入)」

最大で以下の額の金がかかる。

$$ 8万円 \times 12ヶ月 \times 1億2千万人= 115兆2000億円 $$

「日本の借金約1000兆円を10分の1以下に減らし」などは、デノミネーションを行えば額面上は実現可能である。

「核武装します」、これには多額のカネがかかる。

「日本の食料自給率およびエネルギー自給率100%以上を目指します」

以下の公約は物理法則に違反しない。

「地震、津波および気象兵器テロ(人工地震兵器等)対策をします」

人間が知覚可能な地震を人工的に起こすことは可能であり、津波や降雨、旱魃なども、ある程度人工的に操作可能である。またこれは兵器開発ではなく対策なので、そのような兵器が存在しなくても実現可能である。

また、この立候補者は、日本の政治を天皇を元首とする君主制政治に変更する公約をしている。

公約は多数あるが、お互いに矛盾する公約は見つけられなかった。

「東京五輪中止、または超低コストでやります。」と書いてある。金があれば実現可能なことは多いが、支出を削るのに金は使えないので実現は難しいが、中止は可能なので実現可能だ。

中川ちょうぞう

この立候補者の公約は条件付き実現可能である。公約の実現には国家予算を超える金が必要になる。

この立候補者の選挙公報は具体性にかけるが、すべての実現を考えると、おそらく国家予算を上回る額の金が必要になる。

高橋しょうご

この立候補者の公約はすべて実現可能である。

この立候補者の公約をすべて実現するには、国家予算以下の金で足りる。

公約には具体的な対応作に欠けるものが多い。

「少子化対策の公約が守られていたら、私達の回りには今より多くの子供達がいたはずです」という文章があるが、これは誤りである。なぜならば、公約の少子化対策が効果のないものであれば、たとえ公約が守られていたとしても児童人口は増加しない。

せきくち安弘

この立候補者の公約は、全て実現可能である。

この立候補者は憲法改正を公約としている。その他の公約も国家予算以下の金で実現可能である。

この立候補者の提案する日本国憲法の前文には、「国民が投票により選ぶ代表が、常時一カ所に集う新しい国際協調の仕組みとして世界最高会議体(仮地球議事堂)を形成してゆく為に」という文章がある。これを解釈すると、おそらく政治家は24時間365日、一カ所に拘束されるのだろう。

山口敏夫

この立候補者の公約は、すべて実現可能である。

この立候補者の公約は、国家予算以下の金で実現できる。

「2020東京五輪・パラリンピックは・・・一、アスリート選手諸君の、”名誉”をかけた”活躍”に期待し、応援すること」と書いてあり、都民にオリンピック選手の応援を義務付けている。応援したくない都民がいたとしても、文化大革命、大躍進政策のごとく、都民の意思を無視して、都民徴用と強制応援を行えば実現可能となる。

やまなかまさあき

この立候補者の公約は、全て実現可能である。

「今立ち上がれ! 私達(眠れる子羊)よ!」と書いてあるが、都民は人間であり羊ではない。この文章は比喩であろう。しかし、眠れる獅子とか迷える子羊とはいうが、眠れる子羊とは何を意味するのであろうか。

「さあ、はじめよう«レジスタンス»!」とも書いてあるが、侵略や抑圧に対抗する民兵を組織して革命を目指すのではなく、同じく単なる比喩であろう。

「次代を担う!子供たちの輝ける未来«笑顔と笑い声のたえない»の創造を目指します!」と書いてある。「笑顔と笑い声のたえない」を創造するためには、都民に強力な抗うつ剤の摂取を義務付ける必要がある。ディストピアな社会になるが、もちろん実現可能だ。

岸本雅吉

この立候補者の公約は、全て実現可能である。

唯一気になるのが、徴農制だ。

「小学校・中学校時代に、「徴農制」を導入する」、「小学校・中学校時代に数期に分けて「徴農制」を導入します」

少し形は違うがポル・ポトを彷彿とさせる公約だ。

ないとうひさお

この立候補者の公約は、すべて実現可能である。

アメリカ合衆国のような自己責任について書いているが、それを実現するには修正第2条にある、「規律ある民兵は、自由な国家の安全にとって必要であるから、人民が武器を保有し、また携帯する権利は、これを侵してはならない。」のような、武装する権利を都民に認めるべきであるが、そのような言及はしていない。

また、「東京の人口を現在1/2にする」とも書いている。これは虐殺によって人口を減らすのではなく、地方に人を工場や企業を移転させることで実現するという。大躍進政策や文化大革命のような強制的な徴用と動員が必要であるが、もちろん実現可能だ。

望月義彦

この立候補者の公約は、全て実現可能である。

ゼロエミッション都市のために、緑化、木造、木質化を挙げている。おそらく厳しい建築規制が敷かれるのだろう。そのような厳しい建築規制では、東京の経済が他の公約どおりに「世界とともに成長し続ける未来都市」となれるかは疑問だが、十分な金さえあれば可能だろう。

また、「瞑想教育」を公約に入れているため、都民に特定の宗教を強制するものと見える。

小池ゆりこ

この立候補者の公約は、全て実現可能である。

ただし、実現した場合、社会構造を大きく変える公約がある。

「残業ゼロ」を実現するには、たとえ労使協定を結ぼうとも残業は違法になる法律を制定する必要がある。また、もちろん公務員も残業ができないので、国会議員の質問主意書の返答は極めて遅くなるだろう。

「満員電車ゼロ」を実現するためには、電車を拡張するより、東京都の経済を破壊するとか、都民を虐殺するなどしたほうが実現が容易だ。

「多摩格差ゼロ」もよくわからない公約だ。多摩を都心部のように経済的に充実させる公約であろうか。すると大躍進政策や文化大革命ばりに強制徴用と都民動員が必要になる。

宮崎正弘

この立候補者の公約は、全て実現可能である。

この立候補者の公約はあまりにも具体性に欠けるため、考察できることがほとんどない。

上杉隆

この立候補者の公約は、実現不可能である。

「知事給与ゼロ全額返上」と書いてあるが、給与返上は公職選挙法第199条の禁止する寄付にあたるので、現行法では禁止されているが、法律を改正すれば実現可能だ。

「首都直下型地震対策死者ゼロ」と書いてあるが、東京都で大規模な地震が起きた場合に死亡者を0人にできる保証はないので、実現不可能である。

「東京オリンピック運営費を当初のコンパクト案に」と書いてあるが、金さえあれば実現できることは多いが、支出を削るのは金がいくらあっても不可能なので、実現不可能である。

七海ひろこ

この立候補者の公約は、条件付き実現可能である。公約の実現可能性は国外の経済に依存する。

この立候補者は、「経済的にも精神的にも、世界一リッチな都市・東京を実現します」と書いている。これを実現するには、国外のすべての都市が東京の経済規模以下にならなければならない。国外に依存するので条件付き実現可能となる。

考察まとめ

金、法、倫理の制約を無視しても、これほど多くの立候補者の公約が実現不可能になるとは思わなかった。実現不可能な公約を出した立候補者は以下の通り。

マック赤坂、鳥越俊太郎、桜井誠、谷山ゆうじろう、後藤輝樹、中川ちょうぞう、上杉隆、七海ひろこ

以下は実現不可能な公約である。

オリンピックをコンパクトにする

オリンピックは巨大なイベントである。フルチンでかけっこをしていた昔と異なり、今のオリンピックは多数の国家から多数の選手が参加する。例えば、先のロンドン・オリンピックでは、204の国家から、10568人の選手が参加した。選手だけで1万人もいるのだから、これをどうやってコンパクトにせよというのか。参加国の桁を減らし、参加人数の桁も減らすしかない。しかし、おそらく立候補者はそこまでコンパクトにすることは考えていないだろう。

金をかければ実現できることは多いが、金をかけないことを実現するのは難しい。

実現可能性が過去や未来の不確定な結果に依存するもの

無能な都職員を20%クビにする公約を実現するには、現在の都職員の20%が実際に無能でなければならない。すでに確定した結果を変えることはできないので、現在の都職員のうち20%以上が無能でなければ実現できない。

マイスター制度を拡充するには、すでにマイスター制度が存在しなければならない。

ドナルド・トランプはまだアメリカ合衆国の大統領になることが確定していないので、もしドナルド・トランプが大統領にならなかった場合は、毅然とNOをいうこともできない。

日本の国家予算(約200兆円)を超える予算が必要になるもの

政治家は現在の国家予算という上限を認識すべきである。

2016-07-28

C++標準化委員会の文書: P0320R0-P0329R0

[PDF] P0320R0: Thread Constructor Attributes

pthread attributesに相当するstd::thread::attributesを追加する提案。これにより、移植性が高い方法でスレッドのスタックサイズや優先度などを設定できるようになる。

例えば、スタックサイズを指定するには以下のように書く。

std::thread::attributes attrs;
attrs.set_stack_size(4096*10);
std::thread t(attrs, func);

現在の提案ではスタックサイズの指定しか規定していないが、プラットフォームごとの設定も、thread::attributesを拡張することにより、自然な形で追加が可能だ。また、native_handleもサポートされているので、プラットフォームごとのコードも書きやすい。

WindowsのWin32 APIやインターフェースがだいぶ違うので、Windowsでこれを実装するのはすこし面倒だそうだ。

P0322R0: P0322r0 : exception_list

Parallelism TSにある並列実行中の例外をすべてexception_ptrで保持してくれるexception_listというライブラリは便利なのでParallelism TS専用にしておくのはもったいない。汎用的に使えるよう設計すべきだということでexception_listをユーザーが構築できるようにする提案。

exception_listはimmutableな設計になっている。

std::exception_list l ;
// push_back相当
l = std::exception_list( l, std::current_exception() ) ;

exception_listにはムーブがない。コピーはある。そのため、push_back相当のことするには、既存のexception_listのオブジェクトと追加するexception_ptrをコンストラクターに渡して新しいexception_listのオブジェクトを作る必要がある。

[PDF] P0323R0: A proposal to add a utility class to represent expected monad (Revision 2)

標準ライブラリにexpected<T,E>を入れる提案。optionalはexpected<T,bool>とみなすこともできる。さらに、expected<T,E>はvariant<T,E>の特殊なものとみなすこともできる。

expected<T,E>は、T型のオブジェクトかE型のオブジェクトのいずれか保持する。通常はT型のオブジェクトを保持し、エラー時にはE型のオブジェクトを保持している。

他の言語では、eitherという形で存在している機能だ。

P0324R0: One Concept Definition Syntax

関数コンセプトを廃止して変数コンセプトに一本化する提案。

// 関数コンセプト
template <typename T>
concept bool FC() {
    return constraint-expression;
}

// 変数コンセプト
template <typename T>
concept bool VC = constraint-expression;

問題は、現行のコンセプトTSはC++17に入らない見込みなので、あまり深く学ぶ意味がない。

P0325R1: Propose to adopt make_array into the IS

make_arrayを規格に入れる提案。

// std::array<int, 3>
auto a = std::make_array( 1, 2, 3 ) ;

便利だ。

[PDF] P0326R0: Structured binding: customization point issues

構造化束縛のcustomization pointはstd::tuple_sizeとstd::tuple_elementだったが、これは<utility>に依存する。utilityはfreestanding implementationではないので問題だ。そこで、構造化束縛のためのcunstomization pointを新たに作る。

関数の名前は、product_type_sizeとproduct_type_getになる。メンバー関数か、フリー関数として定義しておけば、range-based forのbegin/endに似たADL経由で見つけてくれる。

[PDF] P0327R0: Product types access

P0326と同じ提案だが、設計が少し違う。std::product_type::sizeとstd::product_type::getになっている。また型情報を得るためのtuple_element相当のstd::product_type::elementもある。

[PDF] P0329R0: Designated Initialization

C99にあるDesignated Initializationに似た機能。ただし省略ができない。


struct A { int a, b ; } ;

// すべてがdesignatorであるか、使わないかの二択
// C++: ill-formed
// C99: well-formed
A a = { 1, .b = 2 } ;

// designatorの順番は宣言順でなければならない。

// well-formed
A a = { .a = 1, .b = 2 } ;

// C++: ill-formed.
// C99: well-formed.
A a = { .b = 2, .a = 1 } ;

// designatorの重複は認められない
// C++: ill-formed.
// C99: well-formed 
A a = { .a = 1, .a = 1 } ;

// 配列の初期化はできない

// C++: ill-formed.
// C99: well-formed
A a = { [2] = 2 } 

// ネストはできない。
// C++: ill-formed.
// C99: well-formed.
A a= { .a.b.c.d = 0 } ; 

// リスト初期化はサポートしている
A a = { .a = { } } ;

目的はreadabilityを上げることのみ。

ドワンゴ広告

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

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

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

2016-07-27

C++標準化委員会の文書: P0310R--P0319R0

[PDF] P0310R0: Splitting node and array allocation in allocators

ノードメモリ確保を追加する提案。

listやmapといったリンクリストのデータ構造は、挿入コストがO(1)なのにもかかわらず、最近は敬遠されている。代わりに、挿入コストがO(N)であるunordered_mapが使われている。その理由は、メモリ断片化だ。

メモリ断片化を防ぐために、メモリを一括で確保して切り分けて返したり、解放されたメモリをリンクリストでpoolしておく、ノード専用のメモリ確保方法を、std::allocator_traitsに追加する提案。ノード専用のメモリ確保は、汎用的なpool allocatorよりも速いとしている。

Boost.Containerには同じ発想の実装があるが、C++03時代のstd::allocatorを使っていて、設計が古い。

P0311R0: A Unified Vision for Manipulating Tuple-like Objects

最近、tuple風オブジェクトとunpackingに関しての提案が多いので、そのまとめ。

tuple風オブジェクトとはtupleやpairやarrayのようなクラスや、あるいはアグリゲートのことだ。unpackingとは、構造化初期化のようなtuple風オブジェクトの要素を取り出す操作のことだ。

これ自体は特に新機能の提案をしていないが、tuple風オブジェクトに対するslicing操作が提供されるべきだとしている。例えば、先頭からN個だけunpackingするとか、先頭からN個目から残りをunpackingするとかだ。

[PDF] P0312R0: Make Pointers to Members Callable

メンバーへのポインターを関数呼び出しできるようにする提案。

メンバーへのポインターがメンバー関数を参照している場合、呼び出すのは面倒だ。

struct X
{
    void f() { }
} ;


int main()
{
    auto ptr = &X::f ;
    X x ;
    (x.*ptr)() ;
}

メンバーへのポインターは、クラスのオブジェクトを渡してやらなければならない。

現在、INVOKE(C++17ではstd::invokeとしてINVOKE要件を満たす呼び出し方をするテンプレート追加されている)で呼び出し可能なものは4つ。関数、関数ポインター、関数オブジェクト、メンバーへのポインターだ。

int arg ;
void func( int ) ;
auto func_ptr = &func ;

struct func_class
{
    void operator () ( int ) { } 
} ;

func_class func_obj ;
auto memptr = &func_class::operator() ;
 
func(arg) ; // 関数
func_ptr(arg) ; // 関数ポインター
func_obj(arg) ; // 関数オブジェクト
(func_obj.*memptr)(arg) ; // メンバーへのポインター

メンバーへのポインターだけ文法が違う。

従来、この文法の差異はライブラリで吸収していた。この提案では、普通に呼び出すことができるようにする。第一引数をクラスオブジェクトとみなす。

// (func_obj.*memptr)( arg )と同等
memptr( func_obj, arg ) ;

これはほしい。

P0313R0: Comparison operators in fold-expressions

fold式から比較演算子を消す提案。C++では、a < b < cのような式は慣習的な数学記法として期待される挙動をしない。そのため、fold式で比較演算子が使えても、メタプログラミングやDSL実装の役に立つだけだ。混乱を考えれば、消すほうが望ましい。

P0314R0: Querying the alignment of an object

alignofを式にも適用できるようにする変更。従来、alignofは型にしか適用できなかった。

int x = 0 ;

alignof(int) ; // OK
alignof(x) ; // エラー

この提案では、式にも適用できる。

int x = 0 ;
alignas (16) int y = 0 ;

alignof(x) ; // alignof(int)
alignof(y) ; // 16

[PDF] P0315R0: Lambdas in unevaluated context

Lambda式を未評価式の中でも使えるようにする提案。

従来、lambdaのoperator()はconstexprではなかったし、未評価式の中では使えなかった。その理由は、テンプレートに渡してSFINAEの文脈で考慮させることを禁止するためである。

もしlambdaがconstexprで未評価式の中で使えるとどうなるか。以下のようなコードが書けるようになる。

template < typename T, bool = []{
    T x ;
    T y = x ;
    auto iter = x.begin() ;
    auto end = x.end() ;
    iter != end ;
    *iter ;

    return true ;
}
>
void f()
{

}

これがSFINAEで考慮されるので、lambda式がconceptのように使えるようになってしまう。例えば、上のコードは、T型にデフォルトコンストラクターとコピーコンストラクターとデストラクターとbegin/endメンバー関数があるかどうか。begin/endの戻り値の型はコピーコンストラクターとデストラクター、operator !=とoperator *をサポートしているかどうかによって、SFINAEのルールによってテンプレートのsubstitutionを抑制できる。

問題は、そのような挙動をサポートするには、シグネチャにlambda式全体を含めなければならない。しかし、未評価式での使用を禁止しただけでは、迂回方法がまだある。そこで、エンティティのシグネチャに影響する使い方を直接禁止する文面が入った。

CWG_DEFECTS: C++ Standard Core Language Defect Reports and Accepted Issues

これにより、lambda式を未評価式で使うことを禁止する理由がなくなった。それゆえ、この提案では制限の緩和を提案している。

目的は、tupleなどの型シークエンスへの適用だ。

using sorted = decltype(sort(tuple, [](auto const& a, auto const& b) {
return std::integral_constant<bool, sizeof(a) < sizeof(b)>{};
}));

懸念していた問題が直接解決されたので、無用の制限は緩和すべきだ。

P0317R0: Directory Entry Caching

filesystemにディレクトリキャッシングを追加する提案。

ファイルシステムからディレクトリやファイルの一覧を取得する操作はコストが高いので、キャッシュしておきたい。しかし、下手なキャッシュは問題になる。

キャッシュ機能は、TS時にはあったが削られた。削る際、将来的に考察するとされていた。この提案はその考察である。

[PDF] P0318R0: decay_unwrap and unwrap_reference

decay_unwrapとunwrap_referenceの提案。

unwrap_reference_t<T>は、もしTがreference_wrapper<X>の場合、X &になる。decay_unwrap_t<T>は、もしdecay_t<T>の結果がreference_wrapper<X>の場合、X &になる。

つまり、reference_wrapperをunwrapするためのtraitsだ。reference_wrapperは標準ライブラリにおいて特別な扱いを受けていて、unwrapして扱う挙動になっているライブラリがいくつかある。それならば、標準でunwrapするtraitsが提供されているべきである。

[PDF] P0319R0: Adding Emplace functions for promise<T>/future<T>

future/promiseに対してemplaceを追加する提案。

ドワンゴ広告

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

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

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

2016-07-25

C++標準化委員会の文書: P0301R0-P0309R0

P0301R1: P0301R1: Wording for Unified Call Syntax (revision 1)

統一関数呼び出し記法

f(x,y)という式に対して、まずf(x,y)が妥当なフリー関数fを探し、見つからなければ、x.f(y)が妥当となるxのメンバー関数fを探す機能がまずひとつ。

この提案は、さらにUnified call introducer(統一呼び出し導入子)という文法により、メンバー関数呼び出しからフリー関数を呼び出す機能も提案している。

もともと、上の機能と同じ考え方で、x.f(y)という式に対してf(x,y)と同じ意味を持たせたかったが、様々な理由により没になった。そこで、既存の式とは異なる新しい文法を追加すればそのような機能が追加できるという発想で、unified call introducerの文法が追加された。その文法は.だ。

以下がunified call introducerを使った式となる。

.f(x,y)
.x.f(y)

行頭が.で始まっているが、これはtypoではない。これがunified call introducerだ。

.f(x,y)は、f(x,y)が妥当なフリー関数fの集合と、x.f(y)が妥当なメンバー関数fの集合からなる関数fの集合に対して、オーバーロード解決でbest viable functionを決定する。もともとの統一関数呼び出し記法が、f(x.y)でまずフリー関数を優先し、存在しなければメンバー関数を探しに行くのと違い、フリー関数、メンバー関数のすべてが等しく比較される。

.x.f(y)は、.f(x,y)と同じ意味である。

unified call introducerは、チェインイングをサポートしている。例えば以下のように書くと、

.x.f(y).g.(z)

以下と同じ意味になる。

.g( .f(x,y), z )

何故か。まず最初の.x.f(y)は、先に述べたように.f(x,y)と同じ意味になる。これをexprとする。残りは、.expr.g.(z)なので、これの意味は.g( .expr, z )となる。exprは.f(x,y)だったので、最終的には.g( .f(x,y), z )と同じ意味になる。

もはやアボミネーションと言ってもいいぐらい醜悪な何かになっている。こんなわかりにくい提案は入ってほしくない。

P0302R1: Removing Allocator Support in std::function (rev 1)

std::functionからアロケーターを取り除く提案。

std::functionのコンストラクターにはアロケーターを引数に取るものがあるが、その意味については曖昧である。アロケーターをtype erasureで格納してあとからコピーのために元の型を取り出すのも煩わしい。既存の実装を見ると、libstdc++はそもそもアロケーターを取るコンストラクターを提供しておらず、libc++は、アロケーターを取るコンストラクターこそあるものの、アロケーターは無視され、MSVCの実装はアロケーターを使うものの、代入でtargetが書き換わった場合に再利用されないので、アロケーターの伝播ができない。

std::functionのアロケーターに対しては、様々な規格上の不備や矛盾が指摘されている。

そのため、std::functionからアロケーターサポートを取り除く。これはdeprecated扱いではなく。直ちに取り除く。

P0304R1: C++ Standard Library Issues Resolved Directly In Oulu

Oulu会議で採用された標準ライブラリに対する問題の解決案。

P0305R1: Selection statements with initializer

初期化子つき選択文

以下のようなコードを書くことはないだろうか。

auto obj = get_object() ;

if ( obj.is_valid() )
{
    obj.process() ;
}

一般に、変数を初期化し、初期化された変数の状態によって条件分岐し、分岐先で変数に対して操作を行う処理は多い。しかし、上記のコードには問題がある。まず変数を選択文の外で書かなければならず、選択文のあとにも変数は有効のままだ。変数の利用が選択文だけならば、変数の初期化を選択文に付属させたい。

この提案は、選択文の中で初期化子を使うことができる文法の追加だ。

if ( auto obj = get_object() ; obj.is_valid()
{
    obj.process() ;
}

この改訂版では、switch文に対しても、同様の文法が提案されている。

P0306R0: Comma omission and comma deletion

Cプリプロセッサーマクロ、__VA_ARGS__は、空の引数を受け取ることはできない。

#define F(...) f( __VA_ARGS___ )

// ill-formed
F( ) 

そこで、空の引数も受け付ける__VA_OPT__の提案。

#define F(...) f( __VA_OPT__ )

// f()
F()

[PDF] P0307R2: Making Optional Greater Equal Again

Optionalを再び偉大か同等に!と題された、どこぞの政治スローガンによく似たタイトルの文書。

現在提案されているoptionalは以下のように振る舞う。

optional<X> opt = ....;
assert(( opt >= opt) == true);
assert((*opt >= opt) == true);
assert(( opt >= *opt) == true);
assert((*opt >= *opt) == false);

理由は、optionalのoperator >=は、X型の!operator <を呼んでいるためだ。もしXの型が浮動小数点数だった場合、問題になる。

そういうわけで、正しい挙動は一番下の比較だけだ。いや、正しいというよりは、変えられない挙動というべきかもしれない。すると、一貫性のためには、他の3つの比較も全てfalseになるべきか。それも嫌だ。

この問題を修正するには、optionalのoperator >=が、保持する型のoperator >=を呼べばよい。なので、そのような修正を提案している。

P0308R0: Valueless Variants Considered Harmful

variantの要素型がすべてnoexceptなムーブコンストラクターを持つのであれば、variantはvalueless状態にならないことを保証すべきだという提案。

同様の保証を、std::listにも追加すべきとも提案している。

そして、結局valuelessになるかどうかはnoexceptなムーブコンストラクターがあるかどうかで決まるので、valuelessになるかどうかを判断する、valueless_by_exceptionはいらないのではないかとも提案している。

[PDF] P0309R0: Partial class

partial classの提案。

クラスのprivateなメンバーを変更したとき、そのクラスを使うソースファイルは全て再コンパイルしなければならない。たとえ、privateなメンバーを使わず、またクラスのオブジェクトも生成していないとしてもだ。これを防ぐには、virtual関数を使ったポリモーフィック型を使うか、pimplイディオムを使う必要がある。どちらもメモリ使用量、動的メモリ確保、ポインターのデリファレンスといった追加のコストが必要になる。

そこで、前方宣言を拡張して、partial classを追加する。partial classには、メモリレイアウトを変更しない宣言のみ書ける。

// stack_interface.hpp
partial class stack
{
public :
    void push(int x ) ;
    int pop( ) ;

    bool is_full() ;
    bool is_empty() ;
} ;

partial classは、後続するinternal classで定義できる。

class stack
{
pubic :
    void push( int x ) { buffer[++top] = x ; }
    int pop( ) { return buffer[--top] ; }
    bool is_full() { return top == max_size ; }
    bool is_empty() { top == -1 }

private :
    std::size_t max_size = 100 ;
    int buffer[max_size] ;
    int top = -1 ;
}

partial classは前方宣言と同じように不完全型となる。

partial classは、様々な別名をつけることができる。

partial class stack : export stack_interface1 { ... } ;
partial class stack : export stack_interface2 { ... } ;
partial class stack : export stack_interface3 { ... } ;

実装は別名を全部指定できる。

class stack : partial stack_interface1, partial stack_interface2, partial stack_interface 3 { }

やや筋が悪い提案のように思える。結局、partial classはポインターやリファレンス経由でしか使えないので、完全な定義がある翻訳単位からstaticストレージ、あるいは事前に一括して確保したストレージ上に構築したオブジェクトを、リファレンスかポインター経由でpartial classしか与えられていない翻訳単位に渡して使う形になる。

この提案の価値には疑問だったが、提案者がBMWに所属しているのでようやくわかった。極めて閉鎖的で不自由な組み込みプログラミング向けの機能だ。

組み込みプログラミングなので、メモリの動的確保はない。使うメモリは常に固定で確保している。また、ライブラリはヘッダーファイルとバイナリブロブで提供され、定義がソースコードで提供されることがない。これにより定義を書き換えても、再コンパイルが必要なくなる。ソースコードを見せる必要はない。

極めて筋の悪い提案だ。はっきりいってクソだ。車業界はクソだ。

ドワンゴ広告

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

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

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

22

doorkeeperが有料化するらしい

DoorkeeperというWebサイトがある。これは勉強会、セミナーなどの人が集まるイベントの告知と参加者管理のためのWebサービスを提供している。そのDoorkeeperが有料化するらしい

主催者の皆さまにご利用料をお支払いいただく理由 | Doorkeeper

その理由としては、運営を維持するだけの利益が出ないとのことだ。

Doorkeeprの利益は、イベント参加費の前払いの集金サービスで手数料を徴収することが主なものだったが、そもそもDoorkeeperのイベント主催者の大半は、イベント参加費で利益を上げることを考えておらず、したがって集金サービスもそれほど使われず、利益が出ないとのことだ。

他に利益を上げる方法として、広告や、転職エージェント会社と組むといった方法があるが、広告は広告主がサービスの文脈に沿わないうざい広告しか提案しないのでお断りで、転職会社と手を組むと、利益は転職会社のおこぼれに預かる形になり、転職会社の下で膝を屈することになるのでこれも受け入れがたいという。

確かに、強豪となるWebサービスを提供しているATND(リクルート)とdots(インテリジェンス)は、転職や人材派遣などの事業も行っている。connpass(ビープラウド)は受託開発やpython教育などの事業のようだ。

そこでDoorkeeperは顧客であるイベント主催者から利用料を徴収するそうだが・・・

イベント主催者は利益を目的としていない以上、できるだけコストのかからない方法を選ぶだろうから、あまりうまく行きそうにない。ましてや、無料の競合相手が複数いるような市場では。

Ubuntuでタブレットの画面回転について調べてみた

筆者は長らくタブレットを使っていなかった。これには理由がある。タブレットの多くはiOSやAndroidやWindowsといった不自由なOSが入っていて、極めて使い勝手が悪かったためだ。ところが、今ではx86-64なタブレットも存在する。ARMにGNU/Linuxを入れるのは面倒だが、x86-64なコンピューターであれば、比較的簡単に使えるのではないか。

今回、嫁用のタブレットにUbuntuを入れていろいろと設定したこともあり、自分用にもハックできるタブレットが欲しくなった。そのため、同僚からEndevor TN10Eという極めてCPUの遅いタブレットを格安で買い取っていろいろと遊んでいる。

タッチパネルによるジェスチャーは、Chromiumでは動くが、Firefoxは対応していない。スクリーンキーボードは、筆者がタッチパネルに慣れていないため、とても使いづらい。

Ubuntuと他のOSを比べて気になるのは、画面の自動回転ができないことだ。

画面の回転自体は、xrandrを使えばできる。そこで、以下のようなスクリプトを書いて、画面の回転を切り替えることにした。。

#!/bin/bash

rotation=$(xrandr -q --verbose | grep eDP | egrep -o "(normal|left)" | head -1)

if [ "$rotation" = "normal" ] ; then
    xrandr --output eDP --rotate left
else
    xrandr --output eDP --rotate normal
fi

さて、通常ならば、このスクリプトにわかりやすい名前(rotate-screenなど)をつけてパスの通ったディレクトリに放り込んでおけばいいのだが、タブレットのスクリーンキーボードは打ちづらい。タブレットの利用目的は、移動中にタッチパネルだけでテキストやWebサイトを閲覧することになるだろうから、できれば画面をタッチするだけでこのスクリプトを実行したい。UbuntuのUnityでは、ランチャーに登録するのがいいだろう。

Unityのランチャーにアイコンを登録するには、以下の規格に従った.desktopファイルを作成する必要がある。

Desktop Entry Specification

これを参考に、以下のように書いた。

[Desktop Entry]
Type=Application
Terminal=true
Name=rotate-screen
Exec=/path/to/rotate-screen.sh
StartupNotify=false

このファイルは、例えばrotate-screen.desktopなどと名づけて/usr/local/share/application/か、あるいは~/.local/share/application/の下においておく。あとはこのファイルをGUI上でランチャーにドラッグすれば追加できる。

なぜかTerminal=falseだと、xrandrを呼び出したあとに画面が暗転してマウスカーソルのみ表示される状態になってしまう。

さて、これで画面は回転できるようになったものの、やはり自動で回転させたいところだ。そのためには、コンピューターに搭載されている本体の角度変化を検出するセンサーを読む必要がある、Linuxカーネルでは、Industrial I/O(iio)という名前が付いている。

さて、このiioからセンサー情報を読み取って、D-BUS経由でアクセスできるようにするツールとして、iio-sensor-proxyが存在する。

iio-sensor-proxy/src at master · hadess/iio-sensor-proxy

Ubuntuにはレポジトリに存在するので、apt-get install iio-sensor-proxyしたうえで、systemctl start iio-sensor-proxy.serviceしてmonitor-sensorを実行すれば、加速度、加速角度、光量、コンパスといったセンサーから読み取った結果が表示される。

しかし、調べられたのはここまでで、デスクトップ環境やツールで、ディスプレイの自動回転を行うものがなかなかない。あるにはあるが、どれも適当にでっち上げたプログラムで、あまり洗練された実装ではない。ディスプレイの自動回転を実装するのに必要な道具は全て揃っているので、あとは、あとはiioで加速角度センサーを読み取ってxrandrを叩く簡単なプログラムを書くだけなのだが、果たしてそこまでしてディスプレイの自動回転を実現する理由があるだろうか。そもそも、常にセンサーからの入力を見張って、ディスプレイを回転させるプログラムを実行するということは、それだけ余計に電力を消費するのではないか。

2016-07-23

中古PCを買った

「PCが遅い」と嫁が言う。「10万ぐらいのちゃんとしたPCがほしい」と嫁が言う。

そんな馬鹿な。今時10万円もあれば新品のゲーミングラップトップが買える。観測する限り、嫁はPCでWebブラウザーしか使っていないではないか。閲覧しているWebサイトも、TwitterやFacebookぐらいなものだ。

嫁のPCのスペックを確認するために、Windowsのコントロールパネルを開こうと試みるが、たしかに動作が遅い。型番を調べてググったほうが早そうなほどの時間分またされた挙句、ようやくCPUやメモリ量を確認できた。どうやらAllendale世代のCeleronを積んでいるようだ。

確かに動作が遅いが、不自由でプロプライエタリなソフトウェアであるMicrosoft Windowsについて調べる気にはならない。GNU/Linuxをインストールすればこれよりはマシになるだろう。しかし、聞けばこのPCは卒論を書くのにも使ったという。嫁は全て消しても構わないというが、いろいろとストレージには過去の歴史が残っているであろうから、おそらく消すべきではないのだろう。別のストレージを買ってきて取り替えてからGNU/Linuxをインストールするという手もあるが、スペックも低く、すでに外傷が激しいこの8年ぐらい前のPCをそこまでして温存するべき理由はない。

嫁はコンピューターをよく壊す人間である。スマフォやタブレットは半年も立たないうちに壊してしまうので、最近はガラケーを使っているという。ガラケーのあの形状は、比較的落下時の衝撃に強いのではないかと思う。

以上のことから考えると、数万ぐらいの中古PCを買って、GNU/Linuxをインストールして使わせるのが良いように思う。利用目的には十分な性能と、壊しても惜しくない入手価格であればいいのだ。

そこで、秋葉原にいっていろいろと見て回った結果、AcerのICONIA W700というタブレットを中古で買うことにした。選択した理由は、解像度が1920x1080であるのと、CPUがx86-64で使い勝手がよく、しかもAtomではなくSandy Bridge世代のCore i3-2365Mであることだ。値段は税込みで3万8千円だった。安い理由は、ディスプレイに気泡が入っていることだ。しかし、ディスプレイの隅なので、それほど気にならない場所だ。

タブレットを扱うの初めてだったが、Ubuntuのインストールは何事もなく完了した。

ICONIA W7のBIOSメニューの入り方は本体のWinボタンを押したまま電源ボタンを押し、ベンダーロゴが画面に現れたら両方とも離すという方法であった。ブート順序とSecure bootを無効(私はMicrosoftを信用していないため、Microsoftが署名したバイナリを信用すべき理由がない)にした後、USBストレージに入れたUbuntuをブートしてインストールする。どうやら、Ubuntuのインストーラーはキーボードとマウスを接続していない環境でもインストールが進められるように、スクリーンキーボードが出せるようになっているようだ。今回はキーボードとマウスを使ったので使わなかった。

インストール後に多少の設定をしたのち、使い心地を確かめてみた。UbuntuのUnityは有名なタッチパネルのジェスチャーに対応しているようだ。また、Chromiumはタッチパネルのジェスチャーに対応していたが、Firefoxはまだ対応していなかった。

Ubuntu 16.04には、タブレットの向きに合わせてディスプレイを自動で回転させる機能はなかった。xrandrを使ってディスプレイの回転を切り替える簡単なシェルスクリプトを書いてLauncherにでも設定しておけばとりあえずはいいが、できれば自動で回転して欲しいところだ。GNU/Linuxにはジャイロセンサーの入力を受け取る共通の方法がまだないのだろうか。

さて、今回、初めてタブレットをまともに触ったが、やはり最新のデバイスに触っていないと時代から取り残されると思い、自分用にもタブレットを入手した。Endevor TN10Eだ。これはCPUにAMD A4-1200(Temash)を積んでいて、やや遅い。しかし、ディスプレイの解像度は1920x1080なので、テキストを読むぐらいには使えるだろう。たまたま、同僚がWindowsの再インストールに失敗したものを持っていたので、4500円で買い取った。

Endevor TN10EのBIOSメニューに入るには、音量調整ボタンの+-を同時押ししながら電源ボタンを押す。また、USBキーボードを接続している場合には、F2キーを連打するでも入れる。必要な設定をしたあと、これまたUbuntuをインストールした。

インストール後に使ってみた感想としては、やはりAMD A4-1200は遅い。とはいえ、テキストを読むぐらいには使えそうだ。タブレットの経験に使い潰してみようと思う。

さて、もうひとつ中古PCを買った。dynabook T95だ。

15.6インチの3840×2160ディスプレイ、Haswell世代のCore i7 4710HQ、Radeon R9 M265X、メモリはDDR3が8GB(16GBに増設可能)、ストレージには1TBのハイブリットHDDがついて、8万5千円ほどだった。

やすい理由は、ディスプレイの真ん中よりやや左に縦一直線におそらく1ピクセル幅の常時白点灯ラインがあることだ。とても気になるが、それ以外のスペックは8万5千円で手に入るならば魅力的だ。

さて、Ubuntuをインストールして設定を終え、いろいろと使ってみたが、結論としては、ディスプレイのライン抜けを考慮しても、やはり4Kディスプレイはいいという結論に至った。

結局、我々晴眼者は、コンピューターからの入力方法に眼球を使っている。したがって、効率化のためには眼球にできるだけ多くのピクセルを叩き込むべきである。高PPIは正義だ。高PPIは未来だ。我々は高PPIだ。

また、AMDのGPUはGNU/Linuxで使うのに都合がいい。Ubuntu 16.04では、AMDの不自由でプロプライエタリなバイナリブロブのドライバーは一掃された。もはやUbuntuのレポジトリにはAMDのバイナリブロブなドライバーは存在しない。AMDのGPU用の自由なドライバー実装は十分な品質に達している。

最近、あまりPCのスペックにこだわりがなくなってしまった。いや、実際には逆で、こだわりがありすぎるために、新しくPCを購入する際には、現時点で最高のスペックのPCを入手しなければ気がすまない。30万円だして現時点で最高のスペックのPCを買ったとしても、一年後には陳腐化するし、常に破損、故障の可能性はある。ならば、最初から安い中古PCを使えばいいのではないか。中古なのでスペックには諦めが尽くし、壊れても安ければ気にならない。

2016-07-22

江添ボドゲ会@8月13日

8月13日に江添の自宅でボドゲ会を下記の要領で開催します。

江添ボドゲ会@8月13日 - connpass

気軽にご参加ください。

2016-07-21

C++標準化委員会の文書: P0290R0-P0299R0

P0290R0: apply() for synchronized_value

N4033で提案されているsynchronized_value<T>に対してapply()関数を提供する提案。第一引数に関数オブジェクトを取り、第二引数以降のsyncrhonized_valueを適用する。

synchronized_value<T> s1, s2, s3 ;

int main()
{
    int i = 0 ;
    apply( [&]( auto && s ) { s = ++i ; }, s1, s2, s3 ) ;

P0292R1: P0292R1: constexpr if: A slightly different syntax

この提案はC++17に採用された。以下の内容はまだ公開されていないが採択されたP0292R2の内容を元にしている。

constexpr ifの提案。この提案は条件付きコンパイルではない。実行されない方のブランチのテンプレートの実体化を防ぐif文だ。

constexpr ifの文法は、if文と条件の間にconstexprキーワードを記述する。


if constepxr ( condition )
    statement
else
    statement

conditionは文脈上boolに変換される。もしconditionがfalseならば、1番目のstatementが、trueならば2番目のstatementが、discarded statement(廃棄文)となる。

constexpr ifの実行時の挙動は、if文と同じだ。conditionの値に応じて、どちらかの文が実行される。ただし、コンパイル時の挙動が少し違う。

constexpr ifを持つテンプレートエンティティが実体化されるとき、discarded statement内のテンプレートの実体化は行われない。

template < typename T >
void f( T t )
{
    if constexpr ( std::is_same_v< std::decay_t<T>, std::string > )
    {
        t.compare( "hello" )
    }
    
}

関数fは、実引数にstd::stringが渡された場合、メンバー関数のcompareを呼び出す。もし実引数にstd::stringが渡されなかった場合は、conditionがfalseになるので、constexpr if文のsubstatementはdiscarded statementとなる。テンプレート内のdiscarded statementは、インスタンス化されないので、変数tにメンバーcompareがなかったとしても、コンパイルエラーにはならない。

constexpr ifは、以前提案されていたstatic ifと違い、条件コンパイルではない。テンプレート内で使った時に、discarded statementがインスタンス化されないだけだ。それ以外はif文と同じだ。

例えば、ill-formedなトークン列は、当然ill-formedになる。

// ill-formed
if constexpr ( false )
{
!@#$%^&*()
}

インスタンス化せずともill-formedなテンプレートのコードは当然ill-formedとなる。

template < typename T >
void f()
{
    if constexpr ( false )
    {// ill-formed
        not_found ;
    }
}

このコードでは、非依存名であるnot_foundを使っているが、not_foundは宣言されていないのでill-formedとなる。

constexpr ifを非テンプレートなコードで使うことはできるが、通常のif文と同じ意味しかない。

void f()
{
    // ifと違いはない
    if constexpr ( false )
    {
    }
}

[PDF] P0295R0: Adopt Selected Library Fundamentals V2 Components for C++17

gcdとlcmをLibrary Fundamentals V2から抜き出してC++17に入れる提案。

P0296R2: Forward progress guarantees: Base definitions

Forward Progress Guarantee(ブロックされていないスレッドはいずれは必ず実行が進む保証)を文面に入れる提案。

[PDF] P0298R1: A byte type definition

1バイトを表現するstd::byte型の提案。

std::byte型は、underlaying typeがunsigned charなscoped enum型として追加される。

ビット列を操作する演算子がオーバーロードされている。

char型は符号の有無が未規定で生のバイト列を扱うには不適切な型である。

P0299R1: Forward progress guarantees for Parallelism TS features

タイトル通り、Parallelism TSにおけるforward progress guaranteeの文面の追加。

ドワンゴ広告

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

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

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

2016-07-17

ダイヤルQ2風の電話番号でInstagramやGoogleやMicrosoftから金をむしりとれる脆弱性

セキュリティ研究者が、とても興味深い脆弱性を報告して報奨金をもらった記事が上がっている。

How I Could Steal Money from Instagram, Google and Microsoft – Arne Swinnen's Security Blog

プレミアムナンバーという電話上のサービスがある。これは一時期日本で行われていたダイヤルQ2と同等の仕組みを持つサービスで、プレミアムナンバーという電話番号にかけた電話の通話料は、通常より高い。通話料の差分は、電話サービスの提供元に支払われる。

ダイヤルQ2は電話越しに何らかのサービスを提供して、電話料金で利用料を徴収できる、手軽な仕組みだった。その利用例は、投資顧問、アダルト、占い、人生相談、義援金、ダイヤルアップISPなどに利用されていた。ダイヤルQ2自体は2014年に終わったが、海外ではまだ同等の仕組みをもつサービスが残っていて、一般に、プレミアム通話料金率電話番号と呼ばれている。

ところで、一部のWebサイトは、ユーザーが指定した電話番号に自動的に電話をかける機能を提供している。その理由は例えば以下のようなものだ。

  • ユーザーが人間であることを確かめるCAPTCHA文字列を合成音声で伝え、その文字列をWebサイトに入力させるため
  • 二段階認証のセキュリティトークンとなる文字列を合成音声で伝え、その文字列をWebサイトに入力させるため
  • アカウントに登録した電話番号が本人のものであることを確かめるため

それ以外にも理由はあるかもしれないが、ユーザーの入力した電話番号に自動的に電話をかけるという機能は、もし電話番号としてプレミアム番号が与えられた場合、課金される脆弱性がある。この研究者はこの脆弱性を研究し、それぞれ報告した。

Instagram:アカウントへの電話番号のひも付け

Instagramはアカウントに電話番号をひも付けて検索で見つけさせることができるが、その電話番号に対してSMSで文字列を飛ばし、入力させる。もし、文字列が3分以内に入力されない場合、カリフォルニアから電話をかける。通話時間は17秒だ。

電話番号のひも付けリクエストはレートリミットされているので30秒に一回しか送れない。しかし、Instagramはどんな電話番号にでも電話をかけてくれる。たとえば、eurocall24.comでは0.06ポンド/分の割合で課金できる。

したがって、計算をすると、30分で1ポンド、一日で48ポンド、1年で17280ポンド、1アカウントとプレミアム電話番号で稼げることになる。とはいえ、攻撃者は100アカウントほど用意して攻撃速度を100倍にできる。すなわち、一日で4800ポンド、一ヶ月で144000ポンド、一年で1728000ポンドだ。

また、複数のアカウントで一つのプレミアム電話番号を使いまわせる。

Facebookに連絡したところ、これは想定の範囲内であり、対策も講じてあり、許容範囲内のリスクであるとの返答を得た。手で100アカウントをつくって自動化した攻撃をするのは簡単であると重ねて連絡をとったところ、最終的に、2000ドルの報奨金と、慈善団体への4000ドルの寄付を得た。

Googleの場合: 二段階認証

Googleは二段階認証のための6桁のセキュリティトークンを、ユーザーが指定した電話番号に伝えてくる。電話番号はプレミアム番号も受け付ける。妥当なセキュリティトークンを入力しないと、数回ほど電話を試みたあとに、ブロックされる。

しかし、eurocall24.comは電話のSIPサーバーへの転送をサポートしており、SIPクライアント経由で電話内容を聞くことができる。

すると、あとは音声認識してトークンを入力してログインするまでの工程を自動化すればいいだけだ。

しかし、Googleはログインが試みられてさえいればよく、ログインが成功したかどうかまでは判定していない。電話がかかってきたあとにログイン試行さえ行われていればブロックはされない。そのため、音声認識の部分は省略でき、電話がかかってきたらそのアカウントにログインを試みるスクリプトを書いて自動化した。

電話は、一時間あたり10回に制限されているようだ。一回あたりの通話時間は約35秒だ。したがって、一日に12ポンド、一ヶ月で360ポンド、一年で4320ポンドせしめることができる。しかし、攻撃者は100アカウントを使うことで攻撃速度を100倍できる。一日で1200ポンド、一ヶ月で36000ポンド、一年で432000ポンドだ。Googleの場合は、プレミアム番号もアカウントごとにユニークなものが必要とされる。

Googleにバグ報告すると、「その脆弱性を使ってplease.break.in@gmail.comに侵入してみせよ」と返事が来た。そのような脆弱性ではないことを伝えると、「先のメールは手違いで送られたものである」と返事が来た。その後、「この問題は些細なものでセキュリティ上の懸念はほぼなく、バグ報酬に値しない」というメールが来た。問題が存在することをさらに解説すると、「先のメールは自動的に送信されたもので、送るべきではなかった。まだ調べている」と返事が来た。ただし、「金はユーザーデータに比べれば大した問題ではない。金は重要であるには違いないが、損失分を取り戻すのは、ユーザーの信頼を取り戻すことに比べれば、遥かに容易である。皮肉なことは私も認めるが、ユーザーにとっては理的だw」とのコメントもあった。

Googleの最終的な回答としては、「我々は対策を講じてあるが、電話の仕組み上、完全に防ぐことは難しい。大量の金を引き出す試みは、対策により阻止される。そのため、我々はこの報告に対して報奨金を支払わない判断をした。先に述べた如く、Googleの金銭的損失はユーザーのセキュリティほど重要ではない。とはいえ、取り上げるには値する報告なので、殿堂入りリストには載せておく」

Microsoftの場合:Office 365の体験版の登録

Office 365の体験版の登録にあたって、電話番号を入力してMicrosoftに電話をかけさせることができる。電話番号にはプレミアム番号も受け付ける。番号は7回の登録失敗でブロックされる。

しかし、このブロックをすり抜ける2つの方法が発見された。

電話番号の前にゼロを追加する。ゼロは最大18個追加することができる。また、ゼロの代わりにプレミアム番号の国番号を追加することもできる。これにより、以下の数式の回数のブロック回避が行える

\[\sum_{n=1}^{18}n=171\]

トータルの回数は171+1で172通りだ。

電話番号の末尾に最大4桁のランダムな番号を追加する。

\[\sum_{i=0}^{4}10^i=11111\]

するとトータルの回数は

\[(172 \times 11111) \times 7 = {13377644} {電話回数/プレミアム番号} \]

一回の通話には約23秒かかる。計算を簡単にするために20秒にしよう。プレミアム番号の稼ぎは1分あたり0.15ユーロだ。

\[(13377644/3) \times 0.15 = 668882 ユーロ/プレミアム番号\]

Microsoftは同一の電話番号に対する並列した電話を認めている。攻撃者はこの手法を自動化すること多額の金を掠め取れる。

Microsoftにバグ報告したところ、電話番号の前と後に桁を追加してブロックを回避できる仕様が修正された。報奨金として最小の額である500ドルが支払われた。

Microsoftの回答によれば、電話サービスはアウトソースしているため、Microsoft自体には被害はないが、報奨金を支払う判断をしたそうだ。

「これは確かに脆弱性で、しかもうまいものだ。そのため我々は報奨金を支払う判断をした。セキュリティの立場から言えば、我々は顧客を守ることに重点を置いている。この脆弱性は報奨金に値するし修正に値するが、顧客のデータに対するリスクはない。我々は常に、セキュリティ研究者に、我々がユーザーを守るための役に立つような研究をしてくれることを依頼しているが、この場合、守られたのは我々と我々の協力会社のようだ。」

この脆弱性は大したものだ。

作業が早いプログラマーと遅いプログラマーの差の比は4:1

An empirical study of working speed differences between software engineers for various kinds of task

プログラマーの作業速度には差がある。作業速度が早いことだけをもって優秀なプログラマーとは限らない。そのソフトウェアの保守性が悪いかもしれないからだ。しかし、やはり作業速度の早いプログラマーは優秀と見られがちだ。特に、転職界隈では、優秀なプログラマーは、その作業速度の速さを形容して、「ニンジャ」とか「10倍プログラマー」などというタイトルで喧伝されている。さて実際には、プログラマーの作業速度は、全体としてどの程度違うのか。

プログラマーの作業速度が早いものと遅いものの比は、従来、28:1であると言われてきた。この数字には根拠となる研究がある。1967年にGrantとSackmanが公開した論文[1]で、実験をした結果、28:1であると結論しているからだ。

[1]: "E. Eugene Grant and Harold Sackman. An exploratory investigation of programmer performance under on-line and off-line conditions. IEEE Trans. on Human Factors in Electronics, 8(1):33–48, March 1967."

問題は、その実験内容というのが、たった12人の経験豊富なプログラマーの被験者に2つの問題を解かせただけなのだ。

たったの12人の結果など、真の結果からかけ離れている可能性も大いにある。しかし、この論文はあまり批判されることがなく、28:1という数字のみが独り歩きしてしまい、今日の10倍プログラマーなどという都市伝説を生み出している。

この論文は、十分なサンプル数を集めてみたところ、28:1という比を否定した。

そもそも、プログラミングには様々な種類の作業がある。この論文では、プログラミングを以下の作業に分類した。

  • 保守(既存のコードの理解と変更と拡張)
  • 理解(例、特定の質問に応えるなど)
  • テスト/デバッグ(テストとデバッグ)
  • レビュー(誤りがないかの確認)
  • プログラミング(設計、実装、テスト、デバッグ)
  • 設計
  • コーディング(実装)

分類の判断に迷う場合は、プログラミングか保守に分類した。また、純粋なコーディング単体のみの作業はまれなので、分類上はプログラミングになっている。

結果としては、作業の種類によって、作業速度のばらつきには差が見られた。テスト/デバッグやプログラミングでは差が大きかったが、保守や理解では差が小さかった。レビュー作業の時間は差がとても小さかった。

結論として、プログラマーの作業速度の差は、4:1を超えることはめったにない。バラつきの大きい作業においても、大抵は2:1から3:1であった。

体感では、こういう短期間の実験では、乱数が相当に左右するのではないだろうかと思う。運悪くtypoをして何時間も悩むことがよくあるために。

2016-07-14

C++標準化委員会の文書: P0280R0-P0289R0

P0280R0: Initialize unspecified aggregate members with direct list initialization

以下のコードのコンパイルが通るようになる変更。


struct S
{
    explicit S(int a = 0) : _a{a} { }
    int _a;
};

int main()
{
    S s ; // OK
    S arr[2] = { S{} }; // エラー
}

現行の文面ではコンパイルが通らないが、これはコンパイルが通ることが望ましい。

P0281R0: Remove comma elision in variadic function declarations

昔ながらの可変引数関数でコンマを書かずにellipsisを書ける昔ながらの文法を除去する提案。

以下は合法なC++のコードである。


int f( ... ) ; // 1
int f( int i, ... ) ; // 2
int f( int i ... ) ; // 3

1はポータブルな方法で可変引数を取り出すことができない。どんな引数でも受け付けるので、メタプログラミングではよく使われている。

2は通常使う関数の宣言

3は歴史的経緯により今だに認められている2と同等の意味を持つ関数の宣言。iと...の間にコンマを記述していない。

この文書は、3の文法をC++から除去する提案を行っている。この文法はユーザーの混乱の元であり、Variadic Templatesとの文法の曖昧性が発見されていて、将来の言語拡張の妨げにもなるので、廃止するのが望ましいとしている。

例えば、以下のコードは極めて紛らわしい。

template <class... T> void f(T...); // パラメーターパックを引数に取る関数
template <class T> void f(T...);    // T型と可変引数を取る関数

現行のC規格ではコンマ省略が認められていないので、C言語との互換性の問題はない。

[PDF] P0283R1: Standard and non-standard attributes

実装がサポートしていないattribute namespaceは無視するように注釈を付け加える提案。

現行規格は、実装がサポートしていないattributeに対してどのように振る舞うべきか規定していない。実装がサポートしていないattributeに対してコンパイルエラーを出す場合、ユーザーはattributeをマクロで隠すようになる。これではattributeの存在意義が否定されてしまう。そのため、実装がサポートしていないattribute namespaceは無視すべきである。

[[ezoe::foobar]] int i ; // attributeは無視する

P0284R0: Unqualified enumerators in case labels

switch文のconditionがenum型の場合、そのswtich文に属するcase文では、unqualified lookupでenumeratorが見つけられるようにする提案。

以下のコードが、

enum struct E
{
    foo, bar 
} ;

void f( E e )
{
    switch( e )
    {
    case E::foo :
        break ;
    case E::bar :
        break ;
    }
}

以下のように書けるようになる。

enum struct E
{
    foo, bar 
} ;

void f( E e )
{
    switch( e )
    {
    case foo :
        break ;
    case bar :
        break ;
    }
}

これはぜひともほしい変更だ。switchのconditionがenum型であることがわかっているのだから、非修飾名でもenumeratorが見つけられるべきだ。

P0285R0: Using customization points to unify executors

ユーザー定義のexecutorを渡すcustomization pointを設ける提案。

customization pointとは、std名前空間の下に関数テンプレートがありデフォルトの実装がされている。unqualified nameで呼べばADLによって優先されるように書いておけばそちらが優先される。という仕組み。

P0286R0: A networking library extension to support co_await-based coroutines

ネットワークライブラリをco_awaitに対応させる変更の提案。

[PDF] P0287R0: Simple Contracts for C++

contractサポートの提案。preconditionとpostconditionのみに限定している。attributeで関数宣言に記述できる。

だいたい以下のような形になる。

template < typename T >
class array
{
// データメンバーなど
public :
    std::size_t size() ;

    value_type & operator []( std::size_t i )
    [[ expects: i < size() ]] ;

    void resize( std::size_t n )
    [[ ensures: size() == n ]] ;

} ;

機能的には、assert( condition )を関数の前後に挟むのと大して変わらない。プリプロセッサーマクロではなくコア言語によるサポートがあることと、コア言語でサポートされるので、コンパイラーオプションなので有効無効を切り替えられる実装にできるぐらいか。

文書はもうひとつ、[[ assert : condition]]を提案している。

[PDF] P0288R0:A polymorphic wrapper for all Callable objects

unique_functionの提案。std::functionとほぼ同じだが、コピーコンストラクター、コピー代入演算子がない。そのため、コピーできないcallable型を格納できる。

[PDF] P0289R0: Forward declarations of nested classes

ネストされたクラスの前方宣言を認める制限緩和をする提案。以下のように書けるようになる。

class X::A ;
X::A ptr = nullptr ;

現状では、以下のように書かなければならない。

class X
{
    class A ;
} ;

ネストされたクラスの宣言を囲む直前のクラスの定義の中で宣言しなければならない。不完全型のX::Aしか必要ない場面でも、完全型のXが必要になる。つまり、Xの定義が必要になる。

この制限緩和をする提案。

ドワンゴ広告

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

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

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

2016-07-13

C++14でCommodore 64の開発をする

x86から6502への変換ソフトウェアをつくった上で、GCCでC++14のコードをx86にコンパイルして、そこから6502に変換して、Commodore 64エミュレーターで実行している。

Hacker Newsのツッコミによると、6502ではスタックを表現するのが難しいので、コードもスタックを使うような変数を意図的に避けているのだそうだ。

C++14 for the Commodore 64 [video] | Hacker News

ドワンゴ広告

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

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

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

2016-07-12

C++標準化委員会の文書: P0270R0-P0279R0

P0270R0: P0270R0: Removing C dependencies from signal handler wording

シグナルハンドラーの文面を書き直す提案。

現在のC++規格におけるシグナルハンドラーは、C規格との共通項のみ使えると定義している。

しかし、現在のC++規格が参照しているC規格はC11である。ということは、thread_localが共通項になるが、thread_localは使えるべきではない。

C言事の共通項というと、Cリンケージを指定するextern "C"も使えないということになるが、それではシグナルハンドラー自体が宣言できない。

nullptrを使えない技術的な理由は何もない。

など、様々な問題があるので、この機会に文面を新たに書きなおす提案。

一般に、シグナルハンドラーのなかでは、ロックを発生させない操作のみ許されるべきだとしていて、POF(Plain-Old-Function)や、 signal-safe functionという用語を定義している。

現実的には、シグナルハンドラーの挙動は何も変わらない。既存のコードは動くのもの動かないものも含めてそのままだ。

この文面の変更により、例えばlambda式がシグナルハンドラーの中で使えるようになった。というのも、lambda式の実装にはメモリの動的確保が必要ないから、禁止する理由がないためだ。

P0271R0:

T型を特定の型リストで構築した時に、実際に呼ばれるコンストラクターの実引数の型を知るために、実際に呼ばれるコンストラクターの型を返すtype traits、std::direct_init<T>の提案。

std::variantで例外を投げる変換関数を持った型が渡された場合でも例外安全にvariantを実装するために必要。

P0272R1:Give 'std::string' a non-const '.data()' member function

あまりにもひどいクソ提案なので解説する価値なし。CreateProcessの第二引数は書き換えを行うし第一引数にNULLを渡すべきではないしCreateProcessAを使うべきでもない。

[PDF] P0273R0: Proposed modules changes from implementation and deployment experience

Clangでモジュールを実装して使用した経験から、モジュール規格の改良提案。

モジュール宣言はソースファイルのどこにでも書いていいことになっていたが、その仕様だと、ツールはソースファイル全体をスキャンしてモジュール宣言があるかどうか確認しなければならない。モジュール宣言はソースファイルの最初の宣言に書く制約をつける。

異なるモジュールで名前が衝突した場合、異なるエンティティが与えられるが、名前の衝突に対する対策としては名前空間がすでにある。モジュールでも名前衝突を回避する機能を別に提供すると、名前空間が使われなくなる。名前の衝突を回避する方法としては名前空間のみが提供すべきだ。モジュールの外にでるエンティティは名前が衝突した場合エラー。モジュールの外に出ないエンティティは別々になるようにする。

モジュールの循環参照は禁止されているし、その理由は妥当なものだが、それだと全モジュールに同じ宣言を書かなければならず、結局一つのテキストファイルに書いて#includeする方法から逃れることができない。これではモジュールの意味がない。

これを解決するために、モジュールパーティションという機能を提供する。

[PDF] P0274R0:Clump - A Vector-like Sequence Container with Embedded Storage

組み込みのストレージをオブジェクトに持った連続したメモリー上に確保されるコンテナー、clumpの提案。

clumpはvectorに似ているが、stringのsmall string optimizationに似た実装をしている。Boostのsmall_vectorと発想は同じだ。

例えば、以下のようなレイアウトで実装される。

template < typename T, std::size_t N, typename Allocator = std::allocator >
class clump
{
    char buf[ sizeof(t) * N ] ;
    T * ptr ;
} ;

要素数がN以下の場合はオブジェクト自体に埋め込みのストレージを使い、Nより多い要素数を扱うときには、アロケーターによるストレージの動的確保を行う。

vectorとは互換性がないので、置き換えて使うこともできない。例えば、insertはpair<iterator, bool>を返す。boolは、組み込みのストレージに収まったかどうかを返す。

P0275R0: A Proposal to add Classes and Functions Required for Dynamic Library Load

Boost.DLLに似たshared library(DLLや.so)を扱うためのライブラリの提案。純粋にライブラリだけの提案となっている。

std::shared_libraryは、ファイルパスを指定してshared libraryを読み込み、シンボル名が存在するか調べたり、型とシンボル名をしていしてshared library内の参照を得たりできる。

int main()
{
    std::shared_library mylib(std::filesystem::path{"mylib.so"}) ;

    if ( mylib.has("myfunc") )
    {
        auto && myfunc = mylib.get< void(void) >( "myfunc" ) ;
        myfunc() ;
    }

}

shared libraryの遅延読み込みをしたりすることもできる。また、デフォルトではシステムディレクトリーは探さず、オプションを指定する必要がある設計になっている。この理由としてシステムディレクトリを探すのは遅く、ユーザーはたいてい読み込むファイルの場所をわかっているからとしているが、理解できない。

提案ではDLL(Dynamic Load Library)という用語を使っていて、ライブラリにもdllという名称が出てくるが、インターフェース的にはdlopenのラッパーのように感じる。

例えばロード時のオプションのscoped enumは以下の通り。

    // shared library file load modes
    enum class dll_mode {
        default_mode = 0,
        dont_resolve_dll_references,    // DONT_RESOLVE_DLL_REFERENCES
        load_ignore_code_authz_level,   // LOAD_IGNORE_CODE_AUTHZ_LEVEL
        rtld_lazy,                      // RTLD_LAZY
        rtld_now,                       // RTLD_NOW
        rtld_global,                    // RTLD_GLOBAL
        rtld_local,                     // RTLD_LOCAL
        rtld_deepbind,                  // RTLD_DEEPBIND
        append_decorations,             // See [dll.dll_mode]
        search_system_directories       // See [dll.dll_mode]
    };

DONT_RESOLVE_DLL_REFERENCESとLOAD_IGNORE_CODE_AUTHZ_LEVELについてはWin32 APIのLoadLibraryEx由来、RTLDについては、dlopen由来のオプションだ。

append_decorationsというのは、ロードするファイルパスに、実装のデフォルトのプレフィクスやポストフィクスを付けてロードするオプションだ。例えば、"foobar"という共有ライブラリをロードしようとすると、Windowsならば"foobar.dll"を、GNU/Linuxならば"foobar.so"を読み込もうとする。ロードが失敗した場合、元の文字列でロードを試みる。

search_system_directoriesは、システムディレクトリからもファイルを探すオプションだ。

果たして入るだろうか。

P0276R0: A Proposal to add Attribute [[visible]]

共有ライブラリでシンボル名としてexportしたいエンティティに指定できる[[visible]]の追加

現状では、MSVCはエスクポートするシンボル名に__declspec(dllexport)を書かなければならない。GCCでは__attribute__((visibility("default"))を書かなければならない。また、シンボル名を使う際には、MSVCでは__declspec(dllimport)を書かなければならない。GCCでは書く必要がない。

この結果、以下のような汚らしいプリプロセッサーマクロが書かれることになる。

#if EXPORTING
    #   if MSVC
    #       define API __declspec(dllexport)
    #   else
    #       define API __attribute__((visibility("default")))
    #   endif
    #else
    #   if MSVC
    #       define API __declspec(dllimport)
    #   else
    #       define API
    #   endif
    #endif

この提案は既存の拡張機能を追認するものだ。

[PDF] P0277R1: const Inheritance

const派生の追加提案。const派生すると、基本クラスを改変できなくなる。派生クラスは、基本クラスのコンストラクターは呼べるが、非staticデータメンバーは変更できず、const修飾された非staticメンバー関数しか呼べなくなる。

P0278R0: P0278r0 - volatile solutions

volatileの定義を見直す提案。以下の変更をする。

  1. 未初期化のvolatileオブジェクトからの読み込みは未定義
  2. 実装はvolatileオブジェクトの値を推定してはいけない
  3. const volatileオブジェクトには初期化が必要ない

volatileの利用例として、memory mapped I/Oに使うというものがある。このとき、特定のメモリアドレスに対する読み書きアクセスは、必ず副作用が発生してほしい。

int volatile * p = ... ;

*p = 42 ;
*p = 42 ;
int x = *p ;

例えば、上のコードについて考える。同じアドレスに連続して2回同じ値を書き込んでいる。通常ならば、実装は最適化の際に、書き込みは一回で十分だと考えるかもしれない。書き込んだあとにすぐ読みだしている。実装は最適化の際に、xの値をコンパイル時に決定できる。したがって、実装は最適化の結果、以下のようなコードに変換するかもしれない。

*p = 42 ;
int x = 42 ;

volatileでは、読み書きに伴う副作用を無視しないという意味を持つ。したがって、このような最適化を禁止する。

ということを規定する。

P0279R0: Read-Copy Update (RCU) for C++

RCUライブラリの追加提案。

RCUは、ロックフリーなreader-writerを実現する。

ドワンゴ広告

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

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

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

2016-07-05

C++標準化委員会の文書: P0260R0-P0269R0

P0260R0: C++ Concurrent Queues

concurrent queueライブラリの提案。

使い方は、普通にpushやpopがあり、空きがなかったり空だったりするqueueに待ちなしで操作を試みるtry_pushやtry_popがあり、ブロックせずに操作を試みるnonblocking_pushとnonblocking_popがある。

P0261R0: C++ Distributed Counters

プログラムでは、様々な情報をカウンターで扱う。マルチスレッド環境では、このカウンターはatomic操作しなければならない。問題は、リードの頻度が低く、ライトの頻度が高いカウンターでは、atomic操作を用いるのはコストが高くつく。

このライブラリは、頻度の低いリードのコスト増と引き換えに、頻度の高いライトのコストが低いカウンターを提供する。

使い方としては、基本的にはgeneral_counterを使う。

general_counter<int> counter ;

void f()
{
    // インクリメントとデクリメント
    ++counter ;
    --counter ;

    // +=, -=
    counter += 10 ;
    counter -= 10 ;

    int result = counter.load() ;
}

カウンターへのライトは、戻り値がvoidで、カウンターの結果は返さない。カウンターの値を読むためには、メンバー関数loadを読む必要がある。

カウンターへの操作が集中する場所では、general_counterの代わりに、counter_brokerを使うことができる。counter_brokerはgeneral_counterへの参照を保持し、カウンターへのライトを一旦受け取り、counter_brokerに反映する。


general_counter<int> counter ;
thread_local counter_broker<int> broker( counter ) ;

void high_contention_thread()
{
    while ( true )
    {
        ++broker ;
    }
}

void f()
{
    int value = counter.load() ;
}

うまくライトの集中する部分を切り分けてcounter_brokerを効果的に使わなければパフォーマンスが出ない設計のようだ。

P0262R0: A Class for Status and Optional Value

P0260で提案されているConcurrent queueでは、状態と値を返す。値は返せることもあるし、返せないこともある。現在の設計は、値を返すか例外を投げるメンバー関数と、状態を返し、値はリファレンスで受け取った引数に書き込むメンバー関数とがある。

concurrent queueでは、値を返せないというのは通常起こりうることなので、例外のようなエラー処理を使うのは好ましくない。また、リファレンスで受け取ったオブジェクトに書き込むというのは、値はデフォルト構築可能であることを要求する。

理想的なインターフェースは、状態と値を同時に返すものだ。値は存在しないこともあるので、optionalが使える。しかし、状態と値のtupleを使うのは面倒だ。

すでに書いたように、concurrent queueでは、値を返せないというのは通常起こりうることなので、例外のようなエラー処理を使うのは好ましくない。したがって、状態と値を同時に返す、status_value< Status, Value >というライブラリを新たに提案する。

この提案は筋が悪い。素直にtupleを使ったほうがいい。tupleの使い勝手が悪いのならば、tupleを改良すべきだ。

P0263R1: Core "tentatively ready" Issues

コア言語で既知の問題で解決案が規格入りする準備のできたもの。

P0264R0: auto operator= considered dangerous

auto operator =有害論。

=defaultで定義される特別なメンバー関数でもautoによる戻り値の型推定をさせる作法を定着させようと言う動きに対し、auto operator =は有害であるとする文書。

autoはリファレンスにならない。

struct A
{
    // 戻り値の型はA
    auto operator = ( A & ) { /*...*/ return *this ; }
} ;

クラスAの代入演算子は、、lvalueリファレンスではなく、コピーを返す。

autoの代わりに、auto &やdecltype(auto)が使える。しかし、それでも問題は残る。

struct A { decltype(auto) operator = ( A && a ) { reteurn swap(a) ; } // 100行のコード decltype(auto) swap( A && a ) { /*...*/ return *this ; } } ;

このクラスでは、もしswapの戻り値の型を変更すると、その他の多くの特別なメンバーの戻り値の型まで影響を受けてしまう。保守しにくいコードになる。

文書の上げる最後の点の問題点はよくわからない。swapのような他のメンバーからも使われている基本的なメンバーの変更をしたら、結果がクラス全体に及ぶのは当然だと思うのだが。

[PDF] P0265R0: SG5 is NOT proposing Transactional Memory for C++17

SG5はトランザクショナルメモリーをC++17に提案しない決定をした。時期尚早である。

現行のトランザクショナルメモリーはあまりにも柔軟すぎて、現実のアーキテクチャがサポートするネイティブのトランザクショナルメモリーに落とし込めず、ジャイアントロックによる実装になるだろうから、さもありなん。

[PDF] P0266R0: Removing Restrictions on requires-Expressions

コンセプトのrequiresをbool値を期待する文脈ならどこにでも書けるように制限を緩和する提案。

筆者は現状のコンセプトは入るべきではないと考えている。

[PDF] P0267R1: A Proposal to Add 2D Graphics Rendering and Display to C++,

2Dグラフィックライブラリの提案。

205ページもある、とても長大なドキュメントだ。

内容は普通のグラフィックライブラリだ。

[PDF] P0268R0: up-to expression

シマンテックによるup-to expressionの提案。以下のような式が、

[a..b)

half-openレンジ、a, a+1, a+2, ... , b-2, b-1を生成する。

以下のように使う。

// {0,1,2,3,4}
std::vector<int> v = [0..5) ;
// "01234"
for ( int i : [0..5) )
    std::cout << i ;

up-to式は、慣習的な数学記法に従った文法を持ち、レンジコンセプトを満たす型のオブジェクトを返す。これは遅延評価されるため、メモリ使用量はmake_pair(a, b)程度であり、サイズb-aの配列ではない。up-to式はレンジオブジェクトを期待するところで使うことができる。

有名なLinuxディストリビューションのC++で書かれている11,423件のパッケージのソースコードをパースしてトークンをカウントしたACTCD16によれば、識別子iは20,224,291回使われている。識別子iは最も多く使われている識別子である。平均して、一つのソースファイルあたり8個の識別子iが使われている。

よく書かれるコード例としては、以下のようなものだ。

for ( int i = 0 ; i < 10 ; ++i ) { /*...*/ }

searchcode.comで検索したところ、for文の90%はこのような形をとっている。

このようなfor文のうち、半分はrange-based forに置き換えることができる。残りの半分はup-to式に置き換えることができる。

for ( int i : [0..10) ) { /* ... */ }

up-to式はイテレーターやポインターに使うこともできる。

for ( auto iter : [ v.begin()..v.end() ) )
{
    std::cout << *iter ;
}

up-to式はレンジとしてcomposableである。


using namespace ranges::view;
for (int i : [0..5) | reverse)
    print(i); // outputs 4 3 2 1 0
for (int i : [0..10) | stride(3))
    print(i); // outputs 0 3 6 9
for (int i : [0..10) | stride(3) | reverse)
    print(i); // outputs 9 6 3 0

up-to式は式である。その結果は変数に格納できる。

void f()
{
    auto one_to_five = [0..5) ;

    for ( int i : one_to_five ) ;

    auto f = []( auto x ) { return x ; } ;
    auto a = f( one_to_five ) ;
}

文書では、将来的には[)だけではなく、(), [], (]にも対応できるとしている。

趣旨はわかるのだが、ライブラリでいいのではないのかという気もする。

そして、この提案はコンセプトと、コンセプトによるレンジライブラリが存在することを前提にしているので、使えるとしてもまだまだ先の話だ。

[PDF] P0269R0: Allocator-aware regular expressions

これもシマンテックの提案。std::regexをアロケーターに対応させる提案。

設計上の都合、今更他のライブラリのようにテンプレート実引数でアロケーターを取るわけには行かないので、uses_allocatorを使ってアロケーターを指定する。

シマンテックでは、regexを共有メモリ上に構築するためにregexのあロケーター対応が必須だという。

ドワンゴ広告

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

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

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