2016-03-30

C++標準化委員会の文書: P0190R0-P0199R0

[PDF] P0190R0: Proposal for New memory order consume Definition

memory_order_consumeの定義を変更する提案。RCUだけではなくGCなどにも利用できるようにする。Linuxカーネルでも使えるようにする。

[PDF] P0192R0: Adding Fundamental Type for Short Float

32bit以下のサイズのshort float型の追加の提案。

16bit浮動小数点数は機械学習や画像処理の分野で広く使われるようになっている。IEEE 754-2008では2進数16bitのフォーマットが定義されている。今のARMはネイティブにサポートしている。IntelのCPUでもサポートする計画がある。GPUでは、OpenGLが16bit浮動小数点数を規定している。OpenEXRではfloatの半分のサイズの浮動小数点数を組込型同様に扱えるライブラリがある。nVidiaのCUDAでは16bit浮動小数点数行列があるが、C++規格に存在しないために独自規格になっている。GCCはIEEEやARMのサポートのために__fp16型がある。LLVMにもhalf型がある。

16bit浮動小数点数型は現実の需要があるので、C++標準は早急に取り入れるべきであるとする。

型はshort floatで、浮動小数点数リテラルのサフィックスはsもしくはSだ。


short float s1 = 1.0s ;
short float s2 = 1.0S ;

これは早く入るべきだ。

P0193R0: Where is Vectorization in C++‽

C++に手動のベクトル処理を淹れる方法についての考察。ライブラリベースで入れることを検討している。具体的な話はあまりない。

[PDF] P0194R0: Static reflection (revision 4)

静的リフレクション機能の提案。

この提案では、宣言に何らかの演算子を適用すると、メタオブジェクトという型が生成され、その型を用意された特別なtraitsに渡すことで、名前や型などの詳しい情報を得ることができる。

P0195R0: Modernizing using-declarations

using宣言をpack展開に対応させる提案。

例えば、今提案中のoverloadは、

template< typename Head, typename ... Rest >
struct overloader : Head, overload< Rest... >
{
    using Head::operator() ;
    // コンストラクターなど
} ;

template < typename T >
struct overloader< T > : T
{
    using T::operator () ;
} ;

template < typename ... Types >
constexpr auto make_overloader( Types && ... args )
{
    return overloader< Types ... >( std::forward<Types>...) ;
}

のように再帰的に書かなければならない。これは非効率的だ。

再帰的に書かなければならない理由は、using宣言がパック展開に対応していないからだ。対応していれば以下のように書ける。

template < typename ... Types >
struct overloader : Types ...
{
    using Types::operator() ... ;
} ;

確かに便利だが、利用方法は限られる気がする。あって困ることはないだろう。

[PDF] P0196R0: A generic none_t literal type for Nullable types

型none_tとその値noneの提案。

optionalやanyといったライブラリでは、何も値が入っていないnullな状態になり得る(nullable)。各ライブラリごとにnullを表す別々の型を定義して使うのは冗長であるし、使い勝手も悪い。そこで、nullを意味する共通の型を定義しようという提案。これでジェネリックなコードはnullableな型に対してnullが入っているか確認する場合や、nullを入れる場合、単一の型を扱うだけで良くなる。

これも最近流行りのボキャブラリー型だ。入るべきだろう。

[PDF] P0197R0: Default Tuple-like Access

tupleのようなユーザー定義クラスに対して、tupleのようなアクセス(tuple_size, tuple_element, get)を書くのは面倒だ。そういうアクセスはコンパイラーが自動で生成すればいい。この文書は、tupleのようなアクセスをデフォルトで自動で生成する提案だ。

例えば以下のようなクラス、

struct X
{
    char m1 ;
    short m2 ;
    int m3 ;
} ;
X x{ 1, 2, 3 } ;

に対して、以下のようなtuple風アクセスが何もせずとも自動的に生成される。


tuple_size<X>::value ; // 3
tuple_element< 1, X>::type ; // short
get<2>( x ) ; // int型の値3
get<char>(x) ; // char型の値1

public非staticデータメンバーに対するtuple風アクセスが自動生成される。

protected, privated, virtualな基本クラスがない場合、基本クラスも再帰的に探される。

template  < typename Head, typename ... Rest >
struct X : X< Rest ... >
{
    Head m ;
    X( Head && head, Rest && ... rest )
        : X< Rest ... >( std::forward< Rest >( rest ) ... ),
            m( std::forward<Head>(head) )
    { }
} ;

template < typename T >
struct X<T>
{
    T m ;
    X( T && t )
        : m( std::forward<T>(t) )
    { }
} ;

X< char, short, int > x{ 1, 2, 3 } ;

tuple_size<X>::value ; // 3
tuple_element< 1, X>::type ; // short
get<2>( x ) ; // int型の値3
get<char>( x ) ; // char型の値1

いわば簡易的な静的リフレクションで、シリアライゼーションなどの用途に使えるだろう。ちなみに、提案はConcept TSに依存しているが、見た限り、コンパイル時チェックに使っているだけで、Concept TSの依存を取り除くのは可能のようだ。

いまのConcept TSには依存しないでほしい。

[PDF] P0198R0: Default Swap

クラスに対してデフォルトのswapを自動生成する提案。コンパイラーはデフォルトのスワップを生成する。デフォルトのswapはメンバーごとのswapを行う。

struct X
{
    int m1 ;
    std::string m2 ;
    std::array<int, 10> m3 ;
} ;

void f( X & a, X & b)
{
    // メンバーごとの効率的なswapが行われる
    swap( a, b ) ;
}

std::swapはムーブ可能な型に対しては効率良く動くが、std::arrayのような、ムーブをサポートできない型には効率が悪い。std::arrayのようなクラスは、メンバーごとのswapを行うと効率が良い。そのようなコードは単調で機械的に生成できるので、デフォルトで生成する。swapはfriendなフリー関数として扱われる。

この変更の背景には、swapはコピーやムーブと同じぐらい根本的な操作であるという思想がある。

これは入ってほしい。

[PDF] P0199R0: Default Hash

P0029R0では大抵の型を突っ込めるhash_combineが提案されている。これを使えば、クラス保持する状態のうち、比較に関係のある情報を全部突っ込めばハッシュ計算が素人でも簡単に書けるようになる。問題は、そのようなボイラープレートコードを書くのはダルいということだ。

そこで、そのようなボイラープレートコードをデフォルトで生成されるようにする提案。

P0029とともに入ってほしい提案だ。

ドワンゴ広告

今日は夕方から歯医者だったのでさっさと帰宅した。

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

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

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

WindowsにLinuxサブシステムを載せてUbuntuのユーザースペースが動く未来が来る?

​Microsoft and Canonical partner to bring Ubuntu to Windows 10 | ZDNet

詳しいことは明日発表されるということで、未だに公式の確証はないのだが、MicrosoftとCanonicalが提携してUbuntuをWindowsに持ってくるという話が上がっている。

現在予測されている内容では、これは単にWindows上で動く仮想環境でUbuntu GNU/Linuxを動かすという話ではなく、WindowsにLinux互換サブシステムを実装して、その上でUbuntuのGNU/Linux上で動くユーザースペースをそのまま持ち込むのではないかという憶測が出ている。つまり、aptでパッケージを管理してbashが使えてその他諸々のUbuntuのユーザースペースのCLIツールが全部使えるということだ。

これは、技術的に可能であろうが、Windowsに十分に互換性のあるLinux互換サブシステムを実装するのは不毛なほど金と労力がかかるだろう。

この憶測が正しいとして、どこまで実装するのかも気になる。CLIツールが動く程度だろうか。X.org互換か、あるいはX.orgが動くまで実装するのだろうか。

Linux互換サブシステムを実装する上で一番だるいのはなんだろうかと考えたところ、システムコールではioctlが一番だるいのではないかと思った。/procと/devもサポートしないと大抵のGNU/Linuxユーザースペースのプログラムは動かないので、やはりダルいだろう。

そしてもうひとつ気になるのが、ターミナルエミューレーターだ。まさかcmd.exeではあるまいな。せっかくのGNU/LinuxユーザースペースCLIプログラムが全部動いたとしても、端末がcmd.exeならば全てが台無しだ。

ということを考えると、やはりGNU/Linuxユーザースペースのターミナルエミューレーターも使いたくなり、ということはやはりX.orgが必要になる。

もうひとつの可能性として、Linuxカーネルを使うという手がある。ただ、これはGPLを考えるとありえないように思う。

何にせよ、そこまでしてGNU/Linuxのユーザースペースのツールを使うぐらいなら、最初からGNU/Linuxをネイティブにインストールしたほうがよい。

2016-03-29

C++標準化委員会の文書: P0174R0-P0189R0

P0174R0: Deprecating Vestigial Library Parts in C++17

標準ライブラリの一部をdeprecated扱いとする提案。

以下のライブラリのdeprecated扱いが提案されている。

std::iteratorは基本クラスとして使い、イテレーターの要件を満たすためのネストされた型名をわざわざ手動で定義する手間を省いてくれる。

しかし、本当に手間を省けるかというと疑問だし、クラステンプレートから非修飾名として使うと、依存名ではない問題が発生するので、わかりにくい。たとえば、以下のコードがエラーになる理由は、とてもわかりにくい。

#include <iterator>

template <typename T>
struct MyIterator : std::iterator<std::random_access_iterator_tag, T> {
   value_type data;  // エラー、value_typeが見つからない 
};

maptとmultimapのvalue_compare。

mapとmultimapの実装には使えないし、ユーザーに使われている様子もない。

入力にイテレーターの片方しか取らない版のアルゴリズム(std::mismatchなど)は危険なのでdeprecated扱いにする。

std::allocatorの冗長なメンバー

allocator_traits経由で使うようになったので、冗長なメンバーはdeprecated扱いにする。

文書では、その他の候補としても、いくつかのライブラリを上げている。

vector<bool>は混乱のもとで廃止したいが、ストレージ効率のよい動的に確保されるストレージ上に構築されたビット列コンテナーの代替案が現在はない。

is_literal

is_literalには実用性がない。というのも、ジェネリックなコードで本当に知りたいのは、ある構築が定数初期化であるかどうかであって、型の構築方法の一つがリテラル型になるかどうかなどは実用性がない。

get_temporary_buffer/return_temporary_buffer

もともと不完全なままSTLに残っていたのがそのまま規格にも残ってしまった誰もまともに使っていないライブラリ。

raw storage iterator

今となってはあまり利用価値がない。

無駄な機能は積極的にそぎ落としてほしい。

P0175R0: Synopses for the C library

C++の規格にC言語のライブラリの宣言を追加する提案。今まではヘッダーファイルだけ参照していた。

ユーザーとしては特に変わることはない。

P0177R0: Cleaning up allocator_traits

allocator_traitsのpropagateがイマイチ理解できない理由がわかった。

propagateはアロケーターが状態を持っているかどうかを判別するのに使うのだが、コピー代入とムーブ代入とswapに対して状態があるかどうかを判定するようになっているので、2^3通りの組み合わせがある。当然、ライブラリ側も2^3通りの組み合わせに対処しなければならない。

しかし、現実的に考えれば、アロケーターは状態を持っているかいないかの2通りの場合しかないはずで、原稿の規格はおかしい。これを簡略化するために、既存のpropagate系の判定を全部deprecated扱いにして、単一のpropagateを追加する提案。

これは当然行われるべき変更だ。

P0178R0: Allocators and swap

コンテナーなどのアロケーターを使う型で、アロケーターが状態を持っていて、アロケーターのオブジェクトが等しくない場合、swapが未定義の場合について、それぞれ一時オブジェクトにムーブした上でムーブする方法を使うことで、未定義を回避するフリー関数swapの追加。

P0180R0: Reserve a New Library Namespace Future Standardization

コア言語に新しい機能が入り、ライブラリの設計方法に新しい手法が考案されていき、また現実の需要と事情が変化する中で、近い将来にC++の標準ライブラリには破壊的変更を伴う大幅な変更が必要になるだろう。そのために、新しい名前空間std2とisoを予約する提案。

死蔵されなければよいが。

Ordered By Default

setやmapは、要素の大小比較にoperator <を使っている。これは大抵の場合うまく行くが、世の中には数学的な大小比較を提供していない型も存在する。例えば、。std::complexだ。ただし、complexはsetやmapのための大小比較は提供できる。しかし、そのためには大小比較を定義した上で、比較子をコンテナーに渡してやらなければならない。

struct complex_order
{
    template < typename T >
    bool operator () ( std::complex<T> const & l, std::complex<T> const & r )
    {
        std::tie(l.real, l.img) < std::tie( r.real, r.img ) ;
    }
} ;

int main()
{
    std::set< std::complex<float>, complex_order > s ; 
}

いちいちコンテナに比較子を渡すのが面倒だ。lessを特殊化してやれば明示的に渡す必要はなくなる。

namespace std
{
    template < typename T >
    struct less< std::complex<T> >
    {
        bool operator () ( std::complex<T> const & l, std::complex<T> const & r )
        {
            std::tie(l.real, l.img) < std::tie( r.real, r.img ) ;
        }

    }
} ;

std::set< std::complex<float> > s ;

しかし、これではlessはoperator <を呼び出すものという既存のcontractがこわれてしまう。

そのため、ユーザーにカスタマイゼーションポイントとして、別のテンプレートを提供する。

template <typename T>
struct default_order {
   using type = std::less<T>;
};

template <typename T>
using default_order_t = typename default_order<T>::type;

template < typename Key, typename Compare = default_order_t<Key>,
            typename Allocator = allocator<Key> >
struct set ;

あとは、default_orderを特殊化するだけだ。

template < typename T >
struct default_order< std::complex<T> >
{
    using type = complex_order ;
} ;

この提案は、既存のコードのABI互換性を壊さない。

どんな問題でももう一段階のラッパーをかますことで解決できる。ただし、ラッパーが多すぎるという問題を除いては。

P0184R0: Generalizing the Range-Based For Loop

range-based for loopでイテレーターの先端と終端の型を別にできるように制限を緩和する提案。

Range TSは番兵という概念を導入している。番兵となるイテレーターは別の型でもよい。

struct range
{
    iter begin() const ;
    sentinel end() const ;
}

void f( range const & r )
{

    auto i = r.begin() ;
    auto e = r.end() ;

    for ( ; i != e ; ++i )
    {
        do_somethign( *i ) ;
    }
}

このようなrange型は、現在のrange-based forには渡せない。なぜならば、コード変換のルールが、イテレーターの先頭と終端の型が同じでなければならない制約になっているからだ。この制約をなくし、上のようなrangeをrange-based forに渡せるようにする変更。

適切な変更だ。

P0185R0: Adding [nothrow-]swappable traits (Revision 2)

std::is_swappable<T>, std::is_swappable_with<T, U>, std::is_nothrow_swappable<T>, and std::is_nothrow_swappable_with<T, U>と、その変数テンプレート版(名前が_tで終わるもの)をtype_traitsに追加する提案。

また、utilityにあるswapを、

void swap(optional<T>& rhs)
    noexcept(
        is_nothrow_move_constructible_v<T>
        && noexcept( swap(declval<T&>(), declval<T&>()))
    );

にする。

いい変更だ。

P0186R0: Iterator Facade -

イテレーターを簡単に書けるライブラリの追加。

標準ライブラリに準拠するイテレーターを正しく書くのはボイラープレートコードが多すぎて面倒だ。そこで、このライブラリはC++17とConcept TSとRange TSがあれば簡単にイテレーターが書けるライブラリを提案している。

Concept TSもRange TSもしばらく入らないことを考えると、このライブラリも当分日の目を見ないだろう。

[PDF] P0187R0: Proposal of Bit­field Default Member Initializers

ビットフィールド付きのデータメンバーにデフォルトメンバー初期化しを書けるようにする提案。

struct X
{
    int data : 6 = 42 ;
} ;

文法上の曖昧性を解消してパースを簡単にするために、初期化子には=しか使えない。そして、=の後には初期化子が続かなければならない。例えば{}は書けない。

まあ、いいのではないか。

[PDF] P0188R0: Wording for [[fallthrough]] attribute.

switch文のcaseラベルを通り抜けるのが意図的であると明示的に記述する[[fallthrough]]属性の文面案。

例えば以下のようなコードを書くと、

switch( n )
{
case 2 :
case 3 : // OK、特に何もない
    f() ;
    break ;

case 4 :
    g() ; // 警告、通り抜けてませんか?
case 5 :
    h() ;
}

最近のおせっかいなコンパイラーはcase 4でbreakを書き忘れていないかという警告をしてくる。もし、プログラマーの意図が、nが4の場合は関数gとhを両方呼び出し、nが5の場合は関数hのみ呼び出すというものであれば、上記のコードは正しい。そこで、プログラマーの意図をコード上で伝えるために、[[fallthrough]]を書くことができる。

case 4 : 
    g() ;
    [[fallthrough]]
case 5 :
    h() ;

いちいち書くのが煩わしい以外はいいか。

[PDF] P0189R0: Wording for [[nodiscard]] attribute.

関数の戻り値を使わないと警告される[[nodiscard]]属性の文面案。

// 失敗する可能性があるとても重要な処理
// 失敗した場合はfalseを返す
[[nodiscard]] bool very_important_operation() ;

int main()
{
    // 警告
    very_important_operation() ;
}

また、型に指定した場合、その型を戻り値として使うと、関数に[[nodiscard]]を指定した扱いになる。


[[nodiscard]] struct error_status { } ;
error_status f() ; // [[nodiscard]]がつく

これはC++17に入るコア言語機能の中でも最も一般に役に立つ機能だと思われる。

ドワンゴ広告

ドワンゴではとある一社員が個人的にお菓子神社という霊験あらたかな神社を開いており、参拝者も多い。筆者もポテトチップスという現世利益のために浄賽を投じようと思ったが、ポテトチップスは一袋335kcalもあり、ジョギング換算で5kmに相当し、脂肪換算で46gにあたるため、強い意志力を持ってやめておいた。

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

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

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

2016-03-24

FBIが2週間でiPhoneをクラックする方法について

FBIがAppleに対してiPhoneをクラックするための特別なOSの開発を要求している裁判において、FBIにほぼ証拠捜査のためにほぼ任意の命令を下せる万能な昔の法律、、All Writs Actそのものの合憲性が問われかねない自体に陥っているため、FBI側も栽培を取り下げたいためか、FBIは2週間でiPhoneをクラックする現実的な方法があるので検証すると発言している。

果たしてそれは何なのか。以下の記事で、その方法が考察されている。

その前に、今回のFBIのiPhoneのクラックというのは、正確に言うと、iPhoneのPasscodeを突破したいというものだ。そのために、正解のパスコードを引き当てるまで入力を繰り返す、いわゆるブルートフォースと呼ばれる愚直な攻撃を実施したいのだが、iPhoneにはパスコードの入力を何度か間違えるとストレージからハッシュ値を削除するという仕組みが存在する。ならばそのストレージをコピーすればいいのではないかと思うだろうが、このストレージというのは、通常のストレージではなく、パスコードを格納するためのチップに内蔵されている極小のストレージのことだ。物理的に簡単にコピーできないように作られている。

My Take on FBI’s “Alternative” Method | Zdziarski's Blog of Things

さて、この記事では、FBIが主張する方法について考察しているが、その前に、FBIが取らないであろう方法が列挙されている。

マイクロプロセッサーを破壊すると、Appleですら修理できないであろうから、そのような方法は取らないだろう。また、脆弱性を利用するものは、おそらく検証に2週間以上かかるから違うだろう。監視カメラの映像を洗って容疑者がパスコードを入力しているところを見つけ出すというのも違うはずだ。というのも、FBIは主張する方法が実際に動くかどうか確証がなく、検証すると言っているからだ。

ではどうするのかというと、NANDミラーリングという方法を使うのではないかと推測している。

NANDミラーリングとは、まずパスコードのハッシュ値を記録している極小のストレージを基板から取り外し、コピーして、再び戻し、パスコードのブルートフォースをする。数回の試行で失敗してストレージが消されたら、コピーしたバックアップを戻して再び試行を再開する。

そんな極小のストレージを基板から剥がしてコピーして差し戻すのはにわかに信じがたい。

npmからkikとその他諸々が消されたまとめ

npmとは、node.jsにおけるパッケージシステムのことだ。npmを使えば、他人の書いたnode.jsベースのプログラムとライブラリの入手と利用がとても簡単になる。

そのnpm界隈が混乱している。発端は以下のURLだ。

I’ve Just Liberated My Modules — Medium

Azer Koçuluはkikという名前のnpmパッケージを公開していた。このkikというソフトウェアの中身についてはここでは関係がない。

さて、それとは別に、kik.comというスマフォ用のチャットアプリを出しているKik Interactive社がいて、kikという名前のパッケージをnpmで出したいので、名前を明け渡すように要求した。

Azerはこの要求を拒否した。すると、Kik Interactive社はnpmの管理者に片っ端からメールを投げまくり、そのうちの一人が反応して、Azerの意思に反して、何の法的根拠もなくパッケージを消した。

Azerはこの行動に対し、npmはもはや信頼できないとし、npmに出していたすべてのパッケージを削除した。

そして阿鼻叫喚の世界に突入する。Azerは様々なCLIツールやライブラリをnpmで公開していた。中でも影響力のあったAzerのパッケージは、left-padだ。

azer/left-pad: String left pad

left-padとは、文字列の左側(先頭)を指定した文字数になるように、指定した文字か指定されない場合は空白文字でパディング(埋める)だけの処理を行う簡単なJavaScriptで書かれたleftpadという名前のライブラリだ。空行を抜けば、10行ぐらいしかない簡単なコードだ。

このコードは有名なnpmパッケージで使われていたらしく、間接的に様々なnpmパッケージが依存していたため、世界中で大混乱を引き起こすことになった。

傑作なのは、当のKik Interactive社すらleft-padに依存していたということだ。Kik Interactive社は今回の件について、メールをすべて公開している。

A discussion about the breaking of the Internet — Medium

Kik社はパッケージ取り下げの理由を、ユーザーの混乱を招くためとしているが、すでに公開されたパッケージの中身が変わる方が混乱を招くし、名前だけ見て中身を確認せずにパッケージを使うバカは混乱して当然だ。

npm運営は、これについて議論しているフォーラムを建設的ではないとして閉じるなど、その後の対応も疑問がある。

今回の件について、興味深い指摘がある。

NPM & left-pad: Have We Forgotten How To Program? | Haney Codes .NET

そもそも、leftpadの中身は10行程度のコードである。空行を抜けば、以下の通り。

module.exports = leftpad;
function leftpad (str, len, ch) {
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
    str = ch + str;
  }
  return str;
}

実に多くのパッケージが、このleftpadに依存している。しかし、この程度の関数は数分で書けるのだから、なんでわざわざ依存するんだ?

もっと憂うべきパッケージがある。isArrayだ。このパッケージは一日88万回もダウンロードされていて、2016年2月だけの一ヶ月間に1800万回もダウンロードされていて、72個ものNPMパッケージが依存している。

isarray

isArrayの中身はこうだ。

var toString = {}.toString;

module.exports = Array.isArray || function (arr) {
  return toString.call(arr) == '[object Array]';
};

結局、このコードは本質的にたった一行のコードである。

その他、is-positive-integerという整数が正の整数かどうか判定するパッケージがあるが、これも本質的には4行のコードである。ところが、このパッケージは昨日まで3個もの依存を持っていた(今は0個になっている)

なぜこんなにも多数のパッケージに依存をするのだ?

leftpad, isArray, isPositiveInteger程度、ググる時間を含めても5分程度で書けるはずである。書けない奴はそもそもコードが書けないと言っていい。NPM界隈の人間はコードが書けないのか?

今回の騒動で、以下のような面白いネタパッケージシステムが開発されている。

require-from-twitter

曰く、「Twitterには編集ボタンがないので、最適なJavaScriptモジュールをホストである」

このパッケージシステムを使うには、まずソースコードを自分でツイートして

https://twitter.com/rauchg/status/712799807073419264

しかる後に使う。


const leftPad = await requireFromTwitter('712799807073419264');
console.log(leftPad(1, 5));      // '00001'
console.log(leftPad(1234, 5));   // '01234'
console.log(leftPad(12345, 5));  // '12345'

Twitter社さえ信用すればよい。

ドワンゴ広告

ドワンゴの採用面接を受けると日本Node.jsユーザーグループの「元」代表の@mesoとお話ができるそうだ。

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

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

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

2016-03-18

C++標準化委員会の文書: P0142R0-P0167R1

[PDF] P0142R0: A Module System for C++ (Revision 4)

[PDF] P0143R0: Wording for Modules

[PDF] P0143R1: Wording for Modules

モジュールの提案と文面案。

残念なことに、モジュールはC++17では見送られることが確定した。

[PDF] P0144R1 Structured Bindings

多値から変数宣言と初期化を同時にする文法の提案。

現状では、多値を返す関数の宣言と、多値を返すことは簡単に書ける。

std::tuple< int, double, std::string > f()
{
    return { 1, 2.3, "4" } ;
}

このような関数から、それぞれの型の変数をそれぞれ初期化するのは面倒だ。std::tieを使っても、変数をあらかじめ宣言する必要がある。

int x ;
double y ;
std::string z ;

std::tie( x, y, z ) = f() ;

そこで、以下のような文法で、それぞれの型と値で変数を宣言初期化する機能を提案している。


auto { x, y, z } = f() ;

初期化子としては、std::get<N>をサポートする型(tupleとpair)の他、非staticデータメンバーがすべてpublicなクラス型もサポートされる。また、配列もサポートされていて、それぞれの要素で初期化される。

struct XYZ
{
    int x ;
    double y ;
    std::string z ;
} ;

XYZ f() { return { 1, 2.3, "4" } ; }

auto { x, y, z } = f() ;

int abc[3] = { 1, 2, 3 } ;
auto { a, b, c } = abc ;

これは便利なので入ってほしい。

[PDf] P0145R1: Refining Expression Evaluation Order for Idiomatic C++ (Revision 2)

式の評価順序を固定する提案。

f( a, b, c )という式があったときに、f, a, b, cの式がどの順番で評価されるかは未規定である。例えば、以下のコードの出力結果は未規定である。

void f( int a, int b, int c )
{
    std::cout << a << b << c ;
}

int main()
{
    int i = 0 ;
    f( ++i, ++i, ++i ) ;
}

提案では、ほとんどの式の評価順序を定めているが、唯一、関数の実引数の評価順序は定めていない。そのため、上のコードの出力だけはこの提案でもいまだに未規定である。ただし、f(a)は実引数aより呼び出し可能な式fが先に評価されることが保証されている。

関数の実引数の評価順序が未規定に戻ってしまったのは残念だ。

P0146R1: Regular Void (Revision 1)

void型を完全形にする提案。すなわち、void型のオブジェクトが作れる。

void v1 ;
void v2 = v1 ;
bool b = v1 == v2 ;
void vs[10] ;
auto vp = std::make_unique() ;

テンプレートパラメーターにvoid型を渡した時に例外的に特殊化して対応しなければならない問題が、void型を完全型にするだけで解決する。

[PDF] P0149R0: Generalised member pointers

メンバーポインターの型変換の制限を緩和する提案。

本当に需要がある変換なのだろうか。

[PDF] P0161R0: Bitset Iterators, Masks, and Container Operations

bitsetに2種類のイテレーターを追加する提案。iteratorとindex_iteratorが追加される。

iteratorのoperator *は、イテレーターの指す場所のビットのみがたったbitsetを返す。

std::bitset<3> b{0b110} ;
auto i = b.begin() ;

auto b0 = *i ; // bitset<3>{0b000}
auto b1 = *++i ; // bitset<3>{0b010}
auto b2 = *++i ; // bitset<3>{0b100}

index_iteratorは、イテレーターの指す場所をsize_tで返す。

std::bitset<3> b{0} ;

auto i = b.ibegin() ;
auto i0 = *i ; // 0
auto i1 = *++i ; // 1
auto i2 = *++i ; // 2

既存のコンテナーのイテレーターとは全く違うのでわかりにくい。iteratorは改名すべきだろう。

P0165R1: C++ Standard Library Issues to be moved in Jacksonville

Jacksonville会議で採用が決まった標準ライブラリの問題点の解決案。

P0165R1: Core Language Working Group "ready" Issues for the February, 2016 (Jacksonville) meeting

Jacksonville会議で採用が決まったコア言語の問題点の解決案。

ドワンゴ広告

もうすぐC++17のドラフトが本格的に固まってくるのだが、C++17の新機能として紹介できるわかりやすい大きなコア言語の変更があまりない。どれも小粒な変更ばかりだ。ライブラリはいくつか新しい物が入っているのだが。

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

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

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

2016-03-17

Twitterでつぶやかれている絵文字のリアルタイムなトラッカー

emojitracker: realtime emoji use on twitter

Twitterでつぶやかれている絵文字のリアルタイムなトラッカーがある。

このサービスは近々、Twitterの歴史的に認められていた上限なしAPIアクセスの廃止に伴い、終わる見込みだそうだ。

U+1F647 PERSON BOWING DEEPLY 🙇 — Medium

面白いし参考になるので、今のうちに眺めておこう。

ちなみに、この絵文字トラッカーはユニコードコンソーシアムにおいて絵文字の実際の利用需要の参考に引用されたこともある。

Twitterがまだおおらかな頃、このような面白いサービスを作るために、APIへの上限なしアクセス権を気軽にホイホイ発行していたのだが、Twitterからのメールでの連絡で、近々そのような上限なしアクセスを廃止するので、商用アクセスAPIであるGnipに移行するか諦めろという言われたと報告している。残念なことだ。

Hacker NewsではTwitter社員だと自称する人間が今回の決定について適切な利用法であれば例外的措置もあり交渉も可能であり、我々に交渉もせずに公にしたのは残念であると言い訳がましいことを書き込んでいるが、公開されたメールの文面をみれば、商用APIに移行するか諦めろという最終通告にしか読めないが、公開されているメールの文面は間違っているのか? いかにも言い訳がましいと反論されている。

2016-03-16

C++標準化委員会の文書: P0119R1-P0138R1

今回から、個人的な感想も意図的に書いてみることにした。

[PDF] P0119R1: Overload sets as function arguments

オーバーロードされた関数の名前からlambda式を暗黙に生成する機能の提案。

オーバーロードされた関数名は、関数の集合を表すので、テンプレート実引数に渡すことはできない。

void f( int ) ;
void f( double ) ;

template < typename Func >
void g( Func func ) ;

int main()
{
    // エラー
    // どのfか曖昧
    g( f ) ;
}

これは、lambda式を経由すれば渡すことができる。

g( []( auto && x ) -> decltype(auto) { return f( x ) ; } ) ;

しかし、こんな自明なlambda式をわざわざ書くのは面倒だ。そこで、関数のオーバーロードのセットを指すid-expressionが実引数として指定されたら、このようなlambda式を生成するテンプレートの実引数推定を追加する提案。

テンプレートの実引数推定にルールを追加するので、autoで受けることもできる。

auto less = (<) ;
less( a, b ) ;

確かに便利だが、どの程度の需要があるだろうか。

[PDF] span: bounds-safe views of objects for sequences

連続したストレージとそのサイズを管理して配列のようにアクセスできるライブラリspanの提案。

もともとは、多次元配列としても使えるarray_viewの提案だったが、多次元配列サポートをなくし、また名前も変えてspanとした。Guidelines Support Libraryのspanを

spanは、連続したストレージとその長さを管理できる。つまり、ポインターとその長さを管理するためのクラスだ。

最近のC++の標準ライブラリには、このような"vocabulary type"の提案が多い。vocabulary typeはコードを読みやすくする。

spanはコンパイル時の配列の長さ指定と、実行時の配列の長さ指定の両方をサポートする。

int a[10] ;
// コンパイル時に長さを指定した固定長span
span<int, 10> s1{ a } ; 
// 実行時に長さを指定した動的長さspan
span<int> s2{ a, 10 } ;

spanを経由した配列へのアクセスには範囲チェックが行われる、範囲外アクセスは未定義の動作を引き起こす。固定長と動的長さspanは相互に代入可能だが、長さのチェックはもちろん行われる。

実際の使い方は、arrayとほぼ同じだ。

興味深いのは、P0257の提案されているbyteを使って、standard layout型Tのspan<T>をspan<byte>に変換することで、内部表現を読み書きすることをサポートしている点だ。キャストを手で書かずに済む。

このライブラリは便利なのでほしい。

[PDF] P0123R1: string_span: bounds-safe views for sequences of characters

string_viewがstring_spanに改名された。文字列を共通の方法で操作できるラッパーライブラリ。

string_viewの方がわかりやすい気がするが自転車小屋について議論しても仕方がないのだろうか。

P0124R1: Linux-Kernel Memory Model

Linuxカーネルのメモリモデルについて不文律であるところも含めて完全に解説する文書。

背景として、Linusにatomic操作ライブラリは使い物にならんと言われたので、まずLinuxカーネルにおけるメモリモデルを理解するところから始めるそうだ。

[PDF] P0126R1: std::synchronic<T>

リソースを浪費せずに、あるオブジェクトの値が期待する値になるまで待つライブラリ、std::synchronic<T>の提案

使い方は極めて原始的なcondition variableに近い。

P0128R1: constexpr if

コンパイル時条件分岐constexpr ifの提案。

前回からの変更点は、一つの新しいキーワードconstexpr_ifから、既存のキーワードを連続したconstexpr ifになったこと。

template < typename T, typename ... Rest >
void f(T && t, Rest && ... rest )
{
    constexpr if ( sizeof...(rest) )
    {
        // tを処理
        // 引数ゼロ個のfのオーバーロードは必要ない。
        f( std::forward<Rest>(rest)... ) ;
    }
}

constexpr elseもある。

constexpr if ( ... )
{

}
constexpr else
{

}

どういう形であれ、コンパイル時条件分岐はほしい。

[PDF] P0138R1: Construction Rules for enum class Values

enumを強いtypedefの代わりに使える機能の提案。

内部型が指定されていて、enumeratorの存在しないenumは、縮小変換のないリスト初期化を使えば、キャストを使わずに初期化できるようにする提案。

enum class E : int { } ;

E e{123} ;

void f( E e ) ;

void g()
{
    f( { 123 } ) ;
}

キャストが必要なくなるのは初期化だけなので、これでは使い方が煩わしいことに変わりはない。本物の強いtypedefの方がいい。

ドワンゴ広告

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

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

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

2016-03-10

ファミコンのゲームを3次元化するエミュレーターがすごい

ファミコン画面立体化エミュレータ「3DNES」ベータ版公開。思い出のゲームをリアルタイムに3D変換してプレイ - Engadget Japanese

ファミコンの画像を立体的にして遊べるファミコンエミュレーターが公開されたそうだ。

これはとても面白いコンセプトだ。

金と労力をかけて、特定のゲームに特化したエミュレーターを作れば、もっと精度は良くなるはずで、すでにファミコンエミュレーターはWiiUや3DSでVCという商業的な流通経路もあるので、将来的には公式にこのようなエミュレーターを出すのはあり得る未来だ。

もちろん、一から作るという手もあるが、そのような再実装よりも商業的価値が高いはずだ。

2016-03-07

C++標準化委員会の文書のレビュー: P0063R1-P0096R1

P0063R1: C++17 should refer to C11 instead of C99

C++規格が参照するC言語規格をC99からC11にする変更。

C11の変更がC++とかち合う部分や、C++とCの文面を厳密に解釈した際の奇妙な結果が考察されていて面白い。t

P0067R1: Elementary string conversions, revision 1

整数と浮動小数点数を文字列と相互変換するライブラリの提案。

このライブラリはロケールのように実行時にフォーマットを切り替える機能がなく、かつ、動的メモリ確保も行わない。

用途は、国際化対応が必須ではないパフォーマンスが重要なテキストベースフォーマットのパース。例えば、JSONやXMLなど。

[PDF] P0072R1: Light-Weight Execution Agents

スレッドより制約がある実行単位(SIMDやGPGPUなど)を、実行媒体(execution agent)として扱うための定義を文面に追加する提案。

[PDF] P0073R1: On unifying the coroutines and resumable functions proposals

コルーチンとレジューム可能関数の統一に向けて。

[PDF] P0075R1: Template Library for Parallel For Loops

インデックスベースの並列forループアルゴリズムを追加する提案。

std::for_loop( std::seq, 0, n, [&]( auto i ){ A[i] = B[i] ;} ) ;

これは、以下と同じ意味だ。

for ( unsigned i = 0 ; i != n ; ++i )
    A[i] = B[i] ;

seqをparにすれば、並列実行版になる。

アルゴリズムには、通常のレンジ版と、カウント版がある。レンジ版は、開始インデックスと終了インデックスを取り、イテレーター風にHalf Open Rangeとして終了インデックスに到達するまでインデックスをすすめる。カウント版は、開始インデックスとイテレート回数を取る。インデックスは指定された回数だけ進められる。カウント版のアルゴリズムは、末尾が"_n"という名前になっている。

std::for_loop_n( i, n, f ) ;

は、

for ( unsigned count = 0 ; count != n ; ++count )
    f( ++i ) ;

のような意味になる。

またこの提案はstride版のアルゴリズムも提供する。これは末尾が"_strided"となっている。stride版はインデックスの刻み幅を指定できる。

std::for_loop_strided( i, n, m, f ) ;

は、

for ( auto I = i ; I != n ; I += m )
    f( I ) ;

のような意味になる。

Reductionのサポート。Reductionとは、ロックを使わずに一つの変数を並列に変更でき、最終的な値はシリアルに実行した場合と同じものを得る方法である。その仕組みは、並列実行には変数のviewを見せておき、複数のviewから最終的な値を計算する方法を提供することによって実現している。

float f(int n, float x[]]) {
    float s = 0;
    for_loop(par, 0, n, reduction(s,0.0f,std::plus<float>()),
        [&](int i, float& s_) {
            s_ += x[i] ;
        });
    return s;
}

この例では、変数sの最終的な値は、途中の変更をすべて加算することで得られるので、そのようなreductionを与えている。for_loopの最後の実引数は、Variable Templatesになっていて、reductionをいくつでも受け取ることができる。パラーメーターパックの最後が呼び出し可能な関数オブジェクトとなる。reductionを使った数だけ、関数オブジェクトの呼び出しに実引数が追加される。

inductionのサポート。inductionはループのイテレート回数に応じて線形に増える値である。そのような値をユーザーが手で計算すると間違いの元なので、ライブラリが用意されている。


float* zipper(int n, float* x, float *y, float *z) {
    for_loop(par, 0, n,
        induction(x),
        induction(y),
        induction(z,2),
        [&](int i, float* x_, float* y_, float* z_) {
            *z_++ = *x_++;
            *z_++ = *y_++;
        });
    return z;
}

inductionもreductionと同じく、いくつでも使える。使った数だけ実引数に渡される。上記のコードは、以下のコードと同じ意味である。


float* zipper(int n, float* x, float *y, float *z) {
    for_loop(par, 0, n,
        [&](int i) {
            *(z+i*2)++ = *(x+i)++;
            *(z+i*2)++ = *(y+i)++;
        });
    return z;
}

[PDF] P0076R1: Vector and Wavefront Policies

Parallerism TS(並列アルゴリズム)にベクトル実行ポリシー(SIMDやGPGPU)を追加したいが、単にpar_vecをシングルスレッドに誓言スルテイ土では、制限がゆるすぎてベクトル化できないので、制限を強めた2つの実行ポリシーを追加する提案。

P0077R1: is_callable, the missing INVOKE related trait

is_callable traitsの提案。関数型をテンプレート実引数に与えると、戻り値の型を引数で関数呼び出しできるかどうかを返してくれる。

void f( int, int ) ;

std::is_callable_v< f( int, int ) > ; // true
std::is_callable_v< f( int ) > ; // false

[PDF] P0082R1: For Loop Exit Strategies (Revision 2)

イテレート文を通常通り抜けた場合(条件がfalseになった場合)と、早期に抜けた場合(break)に実行される文を記述できるようにする提案。

ループを実行したあとで、ループが全部回ったのか、途中でbreakしたのかによって、処理を分けたいことがある。その場合、以下のように書かなければならない。

auto it = get_begin(. . .); // Unfortunate that ‘it’ has to be out here.
auto end = get_end(. . .); // Unfortunate that ‘end’ has to be out here.
for (; it != end; ++it)
{
    if (some_condition(*it)) break;
    do_something(*it);
}
if (it == end) // Extra test here.
    do_stuff();
else
    do_something_else(*it);

もし、ループの条件を二回評価できない状況では、以下のようにbreakで抜けたかどうかを保持する変数を書かなければならない。

bool early = false;
while (some_condition())
{
    . . .
    if (test1()) { early = true; break; }
    . . .
    if (test2()) { early = true; break; }
    . . .
    if (test3()) { early = true; break; }
    . . .
}
if (early)
{ . . . }
else
{ . . . }

range-based forの場合はもっと悲惨だ。ループが途中で中断された時のイテレーターが欲しい場合、以下のように書かなければならない。

something_t last; // Extra construction here.
bool early = false;
for (auto&& element : container)
{
    if (some_condition(element))
    {
        last = element; // Extra copy here
        early = true;
        break;
    }
    do_something(element);
}
if (early)
    do_something_else(last);
else
    do_stuff();

そのため、この文書は、イテレート文から条件がfalseになって抜けたが、breakで抜けたかによって実行される文を記述する文法を提案している。


for ( unsigned i = 0 ; i != 10 ; ++i )
{
    if ( !do_something( i ) )
        break ;
}
catch default
{
    do_normal_exit_thing() ;
}
catch break
{// for文で宣言した変数を使うことができる
    do_break_exit_thing(i) ;
}

前回からの変更は文法だ。if forというわかりにくい文法から、catch default, catch breakというわかりやすい文法になった。

これはたまに欲しくなる。

P0088R1: Variant: a type-safe union (v6).

型安全なunion風ライブラリ、variantの提案。

variantは無効な状態、空の状態を許容するかどうかで議論がもめている。

[PDF] P0089R1: On Quantifying Memory-Allocation Strategies (Revision 2)

グローバルアロケーターのかわりにローカルアロケーターを使うことでどのような状況がパフォーマンスの向上につながるのかを検証した文書。

P0091R1: Template argument deduction for class templates (Rev. 4)

コンストラクターによるテンプレートの実引数推定の提案。

tuple<int, double> t{ 1, 2.3} ;

tuple t{ 1, 2.3 } ;

と書けるようになる。

P0096R1: Feature-testing recommendations for C++

C++の機能テストマクロをC++17に対応させる文書。

C++17に入る変更点の一覧にもなっている。

ドワンゴ広告

今日は社内で筆者のask.fmコーパスを用いて機械学習し、文章が質問かどうかを判定するプログラムの作成を試みた社員がいた。結果は、あまり精度がよくなかった。

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

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

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

2016-03-06

靴を買った話

ボルダリングを始めてから筋肉もついたが、食事量も増えたのか、脂肪もつき始めた。その結果、体重がかなり増え、以前ならば登れていた課題が登りにくくなってきた。

これではいかんと一念発起して、2年ぶりにジョギングを再開することにした。京都に住んでいた頃はジョギングをしていたのだが、東京に引越してからはジョギングをしていなかった。まず、ジョギングをするための靴がないので、近所のスポーツ用品店に買いに行った。

スポーツ用品店には様々な靴が並んでいた。しかし疑問なのは、テニス用の靴とバスケットボール用の靴のどこが違うのだろうかということだ。

ジョギング用の靴にも、だいぶ不思議なものがあった。側面に手動のポンプがついていて、シューズをふくらませることによりフィット感を出すという触れ込みの靴があった。そのようなギミックは信用できないので買うのはやめておいた。

結局、1万円ぐらいのジョギング用の靴を買った。

さて、問題は、クライミング用の靴だ。この8ヶ月ほど、スポルティバのジーニアスを履いて登っていたが、そろそろつま先がすり減ってきた。調べると、ジーニアスのソールの厚みは3mmしかないという。足裏感覚抜群という謳い文句のためには、もちろんソールは柔らかく薄くなければならないが、3mmは薄すぎだ。また、一般的に柔らかいソースは、それだけ耐久性も劣るはずだ。

筆者のクライミングシューズ歴は、タランチュラ3ヶ月、ソリューション3ヶ月、ジーニアス8ヶ月だ。どれもスポルティバの靴なので、そろそろスポルティバ以外の靴を試してみたいものだ。

そこで今回は、あまりダウントゥのきつくない靴を試してみることにした。いろいろと見た挙句、Andrea Boldriniのアパッチライトを買うことにした。なかなか見ないメーカーだが、クライミングシューズメーカーとしては高級靴として有名なのだそうだ。価格は他の靴と比較してそれほど高いわけではないが、他の靴がここ数年で値上げしたのに対し、値段が据え置きなので、やはり相対的に高いという。

さて、アパッチライトのソールはAndrea Boldrini独自のFormulaラバーと称するものを使っている。Formulaラバーには2種類あるらしく、アパッチライトが使っているのは、摩擦と耐久性のバランスがいいと謳っているものだ。実際の感覚では、かなり硬いラバーである。摩擦はあまりよくない。アパッチライトのソースの厚みは5mmもあるそうだ。練習用のシューズとしては悪くないかもしれない。

靴の作りはそれほど極端ではない。足入れはしやすい。ソールは土踏まずの前にしか貼られていない。土踏まず部分が靴の中で盛り上がっていて、偏平足気味の筆者の足に当たる。

ヒールの作りはやや気になる。ゴムの継ぎ目の位置が中央に来ているのだが、これはヒールをかけそこねてこすった時に痛まないだろうか。また、ヒール部分は柔らかすぎて、ヒールをかけてかきこむと足が痛い。

とりあえずしばらくはアパッチライトで頑張ることにする。

2016-03-02

普通のコンピューターからAMラジオを鳴らそう

読者の持っている至って普通のコンピューターは、実はAMラジオを鳴らす発信装置が備わっている。

ラジオを鳴らすコードは以下にある。

https://github.com/fulldecent/system-bus-radio

ただしこれはMac OS Xでしか動かないので、C++11に移植したコードが以下になる。また、このコードはスレッドを回して消費電力を上げることにより、オリジナルより出力も上げてある。

https://github.com/EzoeRyou/system-bus-radio

動かし方(GCCの場合)

git clone git@github.com:EzoeRyou/system-bus-radio.git
cd system-bus-radio
make gmain
make grun

Clangの場合、以下のようにする。

make cmain
make crun

そして、AMラジオを近づけて、周波数をいろいろと変更してみよう。なんと、メリーさんの羊が聞こえるではないか。原作者の環境では1580kHz、筆者の環境では1440kHzが最も聞き取りやすかったが、コンピューターによって最適な周波数は変わる。

一体どうしてAMラジオがなるのか。CPUが命令を実行するとき、コンピューターからは電磁波が発生する。電磁波はラジオで観測できる。つまり、別のタイミングで命令を実行してやれば、ラジオに乗るノイズも別になる。適切な周波数で命令を実行すれば、ラジオに乗るノイズも音階を持ったものにできるのだ。

もともとはTEMPESTガイドラインという、アメリカ合衆国のNSAと国防省の勧告によるもので、サイドチャネル攻撃の危険性を周知しているものである。

オリジナルはMac OS X専用の高精度タイマーを使っていて、かつ、SSE命令を使っていた。C++11に移植するために、高精度タイマーには<chrono>, <thread>を使った。SSE命令の代わりに、<atomic>を使った。また、以下のPull Requestと同等のコードを書いて、スレッドで実行することにより、出力を上げた。

boost sound without radio by andryblack · Pull Request #5 · fulldecent/system-bus-radio

ドワンゴ広告

今日はこればかりやっていて、あまり仕事をしていない。これからする。

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

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

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