2017-02-28

C++標準化委員会の文書: P0550R0-P0601R0

興味深いものだけ解説。

[PDF] P0550R0: Transformation Trait uncvref

decayとよく似たtraits、uncvrefの追加。

uncvref<T>::typeはTからCV修飾子とリファレンスを取り除いた型になる。decay<T>::typeとは違い、配列からポインター、関数から関数ポインターへの変換は行わない。

あるべきだ。

[PDF] P0551R0: Thou Shalt Not Specialize std Function Templates!

std名前空間内の関数テンプレートはユーザーが特殊化してはいけないというルールを作ろうと言う提案。関数テンプレートはC++11から特殊化できるようになったので、これまで考慮されてこなかった問題が出てきた。

[PDF] P0552R0:enable_if vs. requires

既存のenable_ifを利用した関数テンプレートに制約を与えるコードを、Concept Liteのrequires実装に置き換えてみたところ、Conceptによる制約付きテンプレートは、制約なしテンプレートよりもpartial orderingで優先されるため、オーバーロード解決の結果に違いをもたらすという警告。

文書では、std::swapをenable_if実装とrequires実装したものを比較して既存のテストに失敗したときの挙動の違いが驚きだったとしている。

既存のコンセプトを使わないコードにコンセプトを使うコードを混ぜると思わぬ挙動の違いに出くわすかもしれない。

P0553R0: P0553R0: Bit operations

ビットイテレーターが提案されているが、それを実装するために必要な基礎的なビット操作関数の追加。

rotl, rotr, popcount, countl_zero, countl_one, countr_zero, countr_oneの追加

rotlとrotrは左右へのロテート。popcountは1のビット数のカウント。countl_zeroは左から連続した0のビットのカウント、_oneは1のビットのカウントcountrは右から。

P0556R0: P0556R0: Integral power-of-2 operations

符号なし整数型に対して適用できる2の累乗に関係したフリー関数を追加する提案。

ispow2, ceilpow2, floorpow2, log2の追加。引数は符号なし整数型でなければならない。

ispow2(x)はxが2の累乗である場合trueを返す。ceilpow2(x)はx以上の最小の2の累乗数を返す。floorpow2はx以下の最大の2の累乗数を返す。log2は2が底のxの対数を返す。小数部は切り捨てられる

[PDF] P0557R0:Concepts: The Future of Generic Programming

Bjarne Stroustrupによるコンセプトの解説。軽く解説(briefly explain)と言っておきながらこの分量はどうなのか。

[PDF] P0559R0: Operating principles for evolving C++

C++標準化の原則のガイドライン。

[PDF] P0562R0:Initialization List Symmetry

クラスのメンバー初期化子の末尾に余計なコンマがあっても許す提案。enumと似ている。

class C
{
    int a, b, c ;
public :
    C( int x, int y, int z ) :
        a(x),
        b(y),
        c(z), // 最後に余計なコンマが付いているが許す
    { }
}

まあ、入れてもそれほど問題にはならないだろうが、今更入れるべきことだろうか。

[PDF] P0563R0:Vector Front Operations

今は昔、賢者たる男女らは非効率的なコードを書く定めの卑しき我らを救い給うために標準テンプレートライブラリを作り給いき。しかるに、賢者は長生なる魔法使いにのみ許されたる危うげなる魔術を我らの前から隠し給いき。天旋り日転じて、田舎の若人に至るまで幾年もの魔術の鍛錬を積むこと久しく、まさに黒魔術をつまびらかにせんとする日、来たれり。何をいいたいかというと、vectorのpush_frontとpop_frontのことだ。

vectorにpush_frontとpop_frontがない理由は、O(N)の非効率的な操作だからだ。vectorへの先頭へのinsertやeraseは、残りの要素をすべて1つづつずらす必要がある。

ところで、最近のハードウェアの事情はすっかり変わってしまった。もはや見かけ上のオーダーより、データの局所性の方が重要になってしまった。局所性のあるデータを隣接するメモリにずらす操作より、メモリ確保の方がはるかにコストのかかる処理となってしまった。

実際、マイクロベンチマークでも先頭へのinsertやeraseは、vectorの方がlistやdequeより速い。

そこで、もはやvectorにpush_frontやpop_frontを付けない理由はない。

ちなみに、vectorにpush_frontとpop_frontをつけると、std::queueの内部コンテナーとして使うことができる。

P0564R0: P0564R0: Wording for three-way comparisons

operator <=>の文面案。

[PDF] P0565R0:Prefix for operator as a pack generator and postfix operator[] for pack indexing

pack-like(パック風)なものを生成するfor式と、packの中からインデックスで要素やサブパックを取り出す式の提案。


template < typename ... Types >
void f( Types ... args )
{
    // 4つめのパラメーターを取り出す
    std::cout << args[3] << std::endl ;
}


int main()
{
    // f(1,2,3,4,5,6,7,8,9)と同じ
    f( for( int i = 1 ; i != 10 ; ++i ) i... ) ;
}   

便利だ。最近、パラメーターパックを第一級市民として扱おうと言う提案が多く見られる。

P0572R0: p0572r0: bit_sizeof and bit_offsetof

ビットフィールドメンバーのビット数を取得できるbit_sizeofとビットフィールドメンバーのクラスの先頭アドレスからのオフセットを取得できるbit_offsetの提案。


struct Foo {
   uint8_t A : 2;
   uint8_t B : 4;
   uint8_t C : 1;
   uint8_t D : 1;
};

int main()
{
    bit_sizeof(Foo::B) ; // 4
    bit_offsetof(Foo::B) ; // 先頭アドレスからのビット数のオフセット
}

ほしい。

P0573R0: abbreviated lambdas

lambda式を使いやすくするために3つの機能を追加。

まず=> expr

// []( auto && x ) -> decltype(expr) { return expr ; }
// と同等
[]( auto && x ) => expr ;

引数の型名省略

// []( auto && x ) => x 
// と同等
[]( x ) => x ;

オーバーロード不可能な単項演算子>>

// static_cast<decltype(x)>(x)
// と同等
(>>x) ;

これはstd::forwardを楽に書くための記法。

[PDF] P0577R0:Keep that Temporary!

一時オブジェクトの寿命を延長するための機能の提案。registerキーワードを再利用する。

この提案は、register exprというregister式を追加する。register式によって、式の結果の一時オブジェクトの寿命はその書かれている文脈のブロックスコープの終わりまで延長される。register式はブロックスコープ内にしか書けない。

以下のようなコードが可能になる。


std::mutex mtx ;

void f()
{
    register std::lock_guard(mtx) ;
    std::string_view = register std::to_string(42) ;
}

lock_guardは変数を束縛するかムーブ代入しておかないと、一時オブジェクトの寿命が尽きてmutexがunlockされてしまう。問題はその変数自体は使わないので冗長な記述が必要になってしまう。

auto ref = std::lock_guard(mtx) ;

to_stringの結果は一時オブジェクトだが、これをstring_viewで受けてしまうと、直接参照で束縛したわけではないので、寿命が尽きてしまう。register式が役に立つ。

一時オブジェクトの寿命を延長する機能は以前にも提案されたが、ライブラリの実装にしか役に立たない仕組みだった。これならばユーザーも使うことができる。

[PDF] P0589R0:Tuple-based for loops

tupleの各要素にrange-based forの文法でアクセスできる機能の提案。ループというよりは展開だ。tupleコンセプトを満たしたものがrange-base forで展開可能になる。

今のConcept Liteが気に入らない。

P0592R0: To boldly suggest an overall plan for C++20

明らかにスタートレック信者が書いたらしきC++20の計画。以下の項目について注力する。

  • モジュール
  • コンセプト
  • レンジ
  • ネットワーク

筆者はコンセプトLite提案を気に入っていないのでコンセプトについては懐疑的だ。

そんなことよりUnicode対応が必要だと思うのだが。

P0593R0: What to do with buffers that are not arrays, and undefined behavior thereof?

mallocで確保したメモリにオブジェクトを構築したものは配列ではないので配列としてアクセスするとC++の規格上未定義の動作になるが、実際そのような処理は書かれている。どうすべきかという問題提起。

P0595R0:The "constexpr" Operator

constexpr演算子の提案。コンパイル時に評価されているかどうかを見分けることができる。

例えば、コンパイル時にはポータブルなコードで計算しないといけないが、実行時には実装依存の高速な方法で計算できるような処理があった場合に、constexpr演算子によってコンパイル時評価されているかどうかで条件分岐できる。


constexpr double power( double d, int x )
{
    if ( constexpr() )
    {
    // コンパイル時評価されているのでポータブルな実装
    }
    else
    {
    // 実行時に評価されているので最適な処理を実行時ライブラリに任せる
        return std::pow( d, static_cast<double>(x) ) ;
    }
}

P0596R0:std::constexpr_trace and std::constexpr_assert

コンパイル時printfとしてのconstexpr_traceとコンパイル時assertとしてのconstexpr_assertの提案。コンパイル時に評価された時にコンソールにメッセージを出力する方法が提供される。

constexpr_assertの存在理由はよくわからない。static_assertがあれば十分ではないか。

P0597R0: std::constexpr_vector<T>

コンパイル時計算の中でも使えるmutableなconstexpr_vector<T>の提案。もちろんpush_backもできる。

[PDF] P0599R0:noexcept for Hash Functions

std::hashの数値、ポインター、標準ライブラリに対する特殊化は例外を投げるべきではないのでnoexceptにしろというアメリカNBからの要求コメント。わかる。

[PDF] P0600R0:applying [[nodiscard]] for C++17

[[nodiscard]]を追加する標準ライブラリの策定。malloc, async, launder, allocateにつける。

これで興味深い文書はすべて解説した。リフレクション周りの文書は無視した。

ドワンゴ広告

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

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

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

2017-02-23

C++標準化委員会の文書: P0501R0-P0549R0

タイトルの範囲で興味深い文書だけ紹介。

[PDF] P0506R0: use string_view for library function parameters instead of const string & / const char *

string_viewで既存の標準ライブラリのstringやchar const *を引数に取る部分を全部置き換える提案。これにより規格の文面も標準ライブラリの定義もかなり短縮される。

ABI互換をぶち壊しそうだがそれに対する考察がない。

[PDF] P0515R0: Consistent comparison

operator <=>の提案。

これまで、様々な種類の比較(strong/weak/partial orderingやequality)について、それぞれstrong_order_less_thanとかweak_order_less_than

operator <=>はthree-way comparisonを提供する。

a <=> bを評価した結果の値rは、a < bの場合 r < 0。a > bの場合r > 0。a == bの場合r == 0となる。

operator <=>によって、比較の種類の問題が解決できる。戻り値の型によって種類を表せばよい。例えばある型がstrong orderingをサポートしている場合は、以下のように書く。

class X
{
    int a ;

public :
    friend std::strong_ordering operator <=>( X const &, X const & ) = default ;
} ;

weak_orderingしか対応できない型の場合は、以下のように書く。例えば、大文字小文字を区別しない文字列型は、weak orderingしか提供できない。


class CaseInsensitiveString
{
    std::string s ;
public :
    frined std::weak_ordering operator <=>( CaseInsensitiveString const & a, CaseInsensitiveString const & b )
    {
        // 大文字小文字を区別しない比較を行う関数
        return case_incensitive_compare( a, b ) ;
    }
} ;

比較の種類を型システムに載せることで、より強い比較を無理やり提供しようとするとコンパイルエラーになる。


class X
{
    CaseInsensitiveString s ;
public :
    // コンパイルエラー
    friend std::strong_ordering operator <=> ( X const &, X const & ) = default ;
} ;

同様に、partial orderingにしか対応できない型は、std::partial_orderingを返す。また、大小比較を提供できず、等価比較しか出来ない場合は、std::strong_equalityやstd::weak_equalityを返す。

さて、残りの比較演算子は、すべてoperator <=>から生成できる。

operator <=>をユーザーが使うこともできるが、通常はその必要はない。というのも、a < bを実現するには、(a <=> b) <0と書かなければならないからだ。

これは今までの提案よりだいぶマシな提案だ。

[PDF] P0533R0: constexpr for <cmath> and <cstdlib>

<cmath>と<cstdlib>の関数の内constexpr実装できるものの基準の考察

[PDF] P0534R0: call/cc (call-with-current-continuation): A low-level API for stackful context switching

call/ccを実現するライブラリの提案。

P0535R0: Generalized Unpacking and Parameter Pack Slicing

これは興味深い提案。

パラメーターパックのスライシングができる機能の提案。

template < typename ... pack >
struct X
{
    // 1番目のパラメーター
    using t1 = [0]pack ;
    using t1a = []pack ; 

    // 2番目のパラメーター
    using t2 = [1]pack ;
    
    // 最後のパラメーター
    using t_last = [-1]pack ;
    // 最後の一つ前のパラメーター
    using t_before_last = [-2]pack ;



    // 3番目から6番目までの3つのパラメーターを持つ新たなパラメーターパック
    using t3 = std::tuple<[2:5]pack> ;
    // 2番目から最後までのパラメーターを持つ新たなパラメーターパック
    using t4 = std::tuple<[1:]pack> ;
    // 1番目から5番目までの4つのパラメーターを持つ新たなパラメーターパック
    using t5 = std::tuple<[:4]pack> ;
    // packと同じパラメーターパック
    using t4 = std::tuple<[:]pack>
} ;

また、以下のような使い方もできる。


struct X
{
    int a ;
    int b ;
    int c ;
} ;

X x ;
[0]x = 1 ; // x.a = 1
[1]x = 2 ; // x.b = 2
[2]x = 3 ; // c.c = 3

興味深いし便利だ。

P0536R0: Implicit Return Type and Allowing Anonymous Types as Return Values

匿名型を関数の戻り値の型に記述できる提案。

struct { int id ; double value } f() ;

この関数の宣言に対して、後から定義を書く際には、以下のように書ける。


decltype(return) f()
{
    return { 123, 5.0 } ;
}

decltype(return)はすでに宣言された関数の戻り値の型を示す。したがって、以下のような例はエラーとなる。


int f(int) ;
float f(float) ;

// エラー、すでに宣言された関数と一致しない
decltype(return) f( double d )
{
    return d ;
}

すでに、関数の戻り値の型推定があるので、以下のようには書ける。


auto f()
{
    struct { int id ; double value ; } result( 123, 5.0 ) ;
    return result ;
}

この提案は、関数のシグネチャをあらかじめ宣言しておけるという機能を提供する。

どうもこのまま受け入れるには問題の多い曖昧な提案だ。

P0538R0: A Qualified Replacement for #pragma once

#pragma onceの機能を標準に追加する提案。

#pragma onceとは主要なC++コンパイラーが実装している非標準機能で、#pragmra onceを書いたヘッダーファイルの#includeを一回のみにする機能だ。

ヘッダーファイルの多重includeを防ぐために、伝統的に以下のようなinclude guardと呼ばれる方法が用いられてきた。

// foo.h
#ifndef _MYLIB_FOO_H_INCLUDED
#define _MYLIB_FOO_H_INCLUDED
...
#endif // _MYLIB_FOO_H_INCLUDED

今回提案されている#onceディレクティブは、ユニークな識別子が必要となる。

#once identifier [ <whitespace> version ]

識別子は::で結合することができる。これは名前空間的に使うことができる。また、識別子の後に空白文字に続けてバージョン番号を記述できる。

すでに一度#includeしたヘッダーと同じ識別子を使っている#onceディレクティブは、残りのヘッダーが無効化される。


// foo.h

#once mylib::foo

提案では、#forgetというディレクティブも提案している。これは既存の識別子を忘れることで、#onceの書かれたヘッダーを多重includeできるようにする機能だ。必要性が理解できない。

結局、一言でまとめれば、提案されている機能は伝統的なinclude guardのシンタックスシュガーだ。

P0539R0: A Proposal to add wide_int Class

wide_int<bytes, signed>型の追加。

long long int型の追加で、64bit長の整数型は表現できるようになったが、それ以上のビット長の整数型を扱いたい場合に標準で表現することが出来ない。そこで、ライブラリで任意のバイト長の整数型を表現できるものを入れようと言う提案。

template<size_t Bytes, bool Signed> class wide_int;

P0540R0: A Proposal to Add split/join of string/string_view to the Standard Library

split/joinをstringとstring_viewとregexに提供する提案。

splitとjoinはメンバー関数という形で提供される。

splitには3種類ある。splitsとsplitfとsplitcだ。これらはセパレーターを引数に取る。文字列をセパレーターで分割する。

セパレーターは、文字、文字列、regexのいずれかだ。セパレーターの文字数がゼロもしくはnull文字ひとつの場合、文字型ひとつづつでsplitされる。

int main()
{
    using std::literals ;
    auto str = "aaa bbb\nccc ddd"s ;

    auto r1 = str.splits(' ') ;
    // r1は{"aaa", "bbb\nccc", "ddd"}

    auto r2 = str.splits("bbb") ;
    // r2は{"aaa", "\nccc ddd"}

    auto r3 = str.splits( std::regex(R"(\s)") ) ;
    // r3は{"aaa", "bbb", "ccc", "ddd"}

    auto str2 = "abc"s ;
    auto r4 = str2.splits("") ;
    // r4は{"a", "b", "c"}
}

splitsは結果をvector<string>で返す。コンテナーをハードコードしている理由は、簡単なライブラリにしたいためだ。splitvは結果をvector<string_view>で返す。こちらは文字列をコピーしないでstring_viewの参照で返す。

vector<basic_string<CharT, Traits> > splits(const basic_string_view<CharT, Traits> &Separator) const
vector<basic_string_view<CharT, Traits> > splitsv(const basic_string_view<CharT, Traits> &Separator) const 

splitfは分割した文字列を関数オブジェクトに渡す。

template <class F>
void splitf(const basic_string_view &Separator,F functor) const

以下のように使う。

int main()
{
    using std::literals ;
    auto str = "a b c" ;
    str.splitf( ' ', []( auto s ) { std::cout << s << '\n' ; } ) ;
}

splitcは分割した文字列をコンテナーにemplace_backしていく。これにより、vector以外のコンテナーを使いたい場合に使える。

int main()
{
    using std::literals ;
    auto str = "a b c" ;
    std::list<std::string> c ;
    str.splitc( ' ', c ) ;
    // cは{"a", "b", "c"}
}

このコンテナーへのリファレンスを取る既存の標準ライブラリに似つかわしくないデザインについて提案著者に質問したところ、お手軽に使いたいからとのこと。あまりよろしくない動機だ。

P0543R0: P0543R0: Saturation arithmetic

C++で符号なし整数は演算結果が最低値、最大値を上回る場合、アンダーフロー、オーバーフローするが、最低値、最大値になって欲しい場合がある。そのためのsaturation演算を提供する提案。

具体的にはコードを見ると一目瞭然。

int main()
{
    // 7
    auto r1 = satadd( 3, 4 ) ;
    // 3
    auto r2 = std::numeric_limits<unsigned int>::max() + 4 ;
    // std::numeric_limits<unsigned int>::max()
    auto r3 = satadd( std::numeric_limits<unsigned int>::max(), 4 ) ;
}

便利だ。

多くのアーキテクチャのSIMD命令は、saturation演算を提供している。

P0544R0: User Injection of Filesystems

std::filesystemにユーザー側が独自の実装を追加することができる昨日の提案。

ユーザースペースによるファイルシステムの実装、例えばアーカイブファイルをファイルシステムとして扱うとか、メモリ内キャッシュをファイルシステムとして扱うような場合に、std::filesystemの実装をユーザー側が提供したいことがある。そのためにstd::filesystemの実装を追加できるようにする機能が必要だ。

また、filesystemの意図的にエラーを発生させることによるエラー時の処理のテストにも使える。

P0545R0: Supporting offsetof for Stable-layout Classes

クラスのメンバーのクラスレイアウト上のオフセットを求めるoffsetofは、standard layout classにしか使えない。しかし、standard layout classは制限が厳しすぎる。例えば、派生やコンストラクターやコピー代入演算子などがあるだけでもstandard layout classから外れる。

しかし、クラスのレイアウトを決定するのに、コンストラクターやコピー代入演算子の存在の有無が影響を与える必要はない。実際、Itanium ABIやWindows x64 ABIはそのようになっている。offsetofを適用できるクラスを増やすために、クラスのレイアウトがコンパイル時に決定できるstable layout classを新たに定義しようという提案。

ある型がstable layout class型となるためには、

  • virtual基本クラスを持たない
  • virtual関数を持たない
  • 非staticデータメンバーはスカラー型かstable layout型か、そのような型の配列型か、リファレンス型であること
  • 非stable layout classを基本クラスに持たない

virtual関数についても、主要な実装方法では、隠しデータメンバーとして実際の関数へのオフセットを保持するvtableを持つ。このメンバーのサイズと位置は固定なのでレイアウトはコンパイル時に計算できる。実際、GCC, Clang, MSVCではそうなっている。しかし、今回の提案では、virtual関数を持つ型がstable layout classを満たすことについてはconditionally supportedに留める。将来的には緩和を考える。

virtual基本クラスはvirtual関数と同じように隠しデータメンバーとして持つ。virtual関数とは違いそのサイズと位置は可変だ。最終的な最も派生されたクラス型がわかっているならばコンパイル時にレイアウトの計算ができるが、一般的にはコンパイル時に計算できないので、サポートしない。

ドワンゴ広告

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

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

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

2017-02-22

アンチウイルスソフトウェアの利用者は過失が問われるべき

Google and Mozilla's message to AV and security firms: Stop trashing HTTPS | ZDNet

GoogleとMozillaの調査によれば、世の中のほとんどのアンチウイルスソフトウェアは通信内容を傍受するためにブラウザーに対してMITMを仕掛けている。

MITM(Man In The Middle)とはTLS(HTTPS)接続の証明と暗号を無効化するための方法で、中間者攻撃とも呼ばれる。

HTTPSにはふたつの役割がある。通信内容の暗号化と、通信相手と通信内容の証明だ。

通信内容が暗号化されていない場合、秘密の情報(クレジットカード番号など)が途中で通信を傍受している悪意ある攻撃者に筒抜けになってしまう。それを防ぐために通信を暗号化したいところだが、それだけでは不十分だ。

まず、通信相手が本人である保証がないし、通信内容は本人のものである保証もない。通信経路の途中で傍受できるということは、当然書き換えもできるはずだ。

通信相手が本人であり、通信内容が途中で改変されていないことを示すための証明方法がある。これで問題は全て解決したかというと、そうでもない。

通信をしたい二者の間に中間者が挟まって、二者のどちらにもHTTPSで使われている証明を行うことで、どちらとも相手と通信しているように錯覚させることができる。これを中間者(Man in the middle)攻撃という。

ただし、この中間者攻撃というのは、通常はうまくいかない。何故ならば、中間者の証明書を信頼しなければならないからだ。

ところで、アンチウイルスソフトウェアは、コンピューターの中で管理者権限で動くソフトウェアである。アンチウイルスソフトウェアは自分の証明書を信頼させることができる権限を持っている。すると、アンチウイルスソフトウェアはMITMができる。

なぜアンチウイルスソフトウェアがMITMをするかというと、通信内容を傍受して、悪意あるソフトウェアが紛れ込んでいないかを監視するためだ。そのため、アンチウイルスソフトウェアの中間者攻撃の意図に悪意はない。しかし、その実装は雑である。

多くのアンチウイルスソフトウェアは、中間者攻撃の実装に不具合や脆弱性を抱えている。その結果、ユーザーのセキュリティが弱められる。

さらに、アンチウイルスソフトウェアは管理者権限で動作し、カーネルも含む他のソフトウェアにコード注入する。これも脆弱性をうみだす。

ましてや、現代の悪意あるソフトウェアは単にパターンマッチやヒューリスティックによる検出で対応しきれない。

アンチウイルスソフトウェアを実行することはセキュリティを高める事にはならず、逆に下げることになる。したがって、アンチウイルスソフトウェアを使った結果セキュリティを弱め、コンピューターに悪意あるコードの実行を許し、他人に被害を与えた場合、アンチウイルスソフトウェアを実行している人間は過失が問われるべきである。

アンチウイルスソフトウェアは詐欺なので直ちに使用を中止すべきである。

2017-02-15

C++標準化委員会の文書: 2017-02のまとめ

2017-02 Pre-Kona mailingsが公開されている。

#MAILING2017-0: ISO/IEC JTC1/SC22/WG21 - Papers 2016

参考書の執筆に注力したいため、この記事では改訂版の提案のうち興味深い文書を取り上げる。

[PDF] N4637: Working Draft, Extensions to C++ for Modules

モジュールのドラフト

[PDF] N4640: Working Draft, Standard for Programming Language C++

現在のドラフト。変更点はeditorial上のものにとどまる。valarrayの文面が最新の用語を使って書き直された。

[PDF] P0045R1:Qualified std::function signatures

constなstd::functionにconstではない関数オブジェクトを代入するとconstなオブジェクトが変更できてしまう問題がある。

struct delay_buffer {
int saved = 42;
int operator () ( int i ) { return std::exchange( saved, i ); }
};
// Small object optimization — no heap allocation.
const std::function< int( int ) > f = delay_buffer{};
assert ( f( 1 ) == 42 );
assert ( f( 5 ) == 1 );

この問題への対処として、std::functionのテンプレート実引数にconst修飾を書けるようになる。既存のconstなstd::functionは[[deprecated]]を利用してdeprecated扱いであることを明示した上でconst_castを使う

std::function< void() > const f = []() mutable {} ;
f() ; // [[deprecated]]警告付きで動作する

// コンパイルエラー
std::function< void () const > const g = []() mutable {} ;

これは便利だ。

[PDF] P0052R3: Generic Scope Guard and RAII Wrapper for the Standard Library

汎用RAIIラッパーライブラリ、だいぶ仕様が固まってきたので、これ以上大きな変更はなさそうだ。

[PDF] P0059R3: A proposal to add a ring span to the standard library

固定長リングバッファーを実装するring_spanの提案。ring_spanはストレージを管理せず、コンストラクターでcontiguous iteratorで渡されたストレージを使う。

この提案では、ring_spanからイテレーターを得るbegin/endが削除された。ring_spanはストレージを所有しないため、イテレーターを提供するのは好ましくないとのことだ。

[PDF] P0082R2: For Loop Exit Strategies (Revision 3)

繰り返し文を条件式がfalseになって抜けたのか、break文で抜けたのかによって、繰り返し文を抜けた後で条件分岐したいことがある。しかし、C++ではそれを直接表現する方法がないので、極めて冗長かつ非効率的な方法で書かなければならない。

bool did_break = false ;

for ( ... )
{
    if ( ... )
    {
        did_break = true ;
        break ;
    }
}

if ( did_break )
    ... ;
else
    ... ;

この提案はC++に繰り返し文のあとにbreakで抜けたかどうかで条件分岐する文法を追加するものだ。この改訂版では、既存のキーワードを使い回すのではなく、新しいキーワードを追加する設計に改められた。


for ( int i = 0  ; is_completed(i) ; ++i )
{
    if ( is_error() )
        break ;
}
on_complete
    do_normal_things() ;
on_break 
    do_abnormal_things() ;

キーワードはon_complete/on_breakだ。

だいぶわかりやすくなった。

P0091R4: Template argument deduction for class templates (Rev. 7)

deduction guideをdelete定義できるようにする提案。まあ、必要になる場合もあるかもしれない。

P0103R1: Overflow-Detecting and Double-Wide Arithmetic Operations

オーバーフローが検出できる整数の四則演算と左シフト演算のライブラリの提案。オーバーフローの有無がbool型の戻り値で、演算結果が実引数に渡したポインター経由で得られる関数と、ひとつの型で返す関数がある


template <typename T> bool overflow_add( T* result, T a, T b );

1つの型で返す関数の方は、split_lowerとsplit_upperで上位下位に分けることができる。

P0104R1: Multi-Word Integer Operations and Types

固定長整数ライブラリの提案

template<int words> multi_int;
template<int words> multi_uint;

演算子がオーバーロードされていて普通に組み込みの整数型のように使える。問題は、現在の文面では、1ワードが何バイトなのか実装依存だということだ。

P0105R1: Rounding and Overflow in C++

浮動小数点数の丸め方とオーバーフローの挙動を指定して演算できるライブラリの提案。

P0237R5: Wording for fundamental bit manipulation utilities

整数型をビットのコンテナーとみなしてビットへのイテレーターなどのアクセス方法を提供するアダプターライブラリの提供。おそらく規格に入る。

[PDF] P0267R3: A Proposal to Add 2D Graphics Rendering and Display to C++,

2Dグラフィックライブラリのドラフト。よくもここまでまとめたものだ。文字列描画機能はないようだ。

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

shared libraryやWindowsのDLLのように、動的に関数やクラスの実装をプログラムにロードして使えるライブラリの提案。果たして標準化できるのだろうか。

P0316R0: allocate_unique and allocator_delete

指定したアロケーターでストレージを確保してunique_ptrを構築するライブラリallocate_uniqueの提案。すでにshared_ptrに対するallocate_sharedはあるので、その補完。

[PDF] P0352R1: Smart References through Delegation (2nd revision)

operator .ではなく派生を使ってスマートリファレンスを実装できる機能の提案。operator .よりよほどマシな文法と意味だ。こちらが採用されるべきだ。

P0355R2: Extending <chrono> to Calendars and Time Zones

<chrono>を日付に対応させる提案。これでようやくCライブラリを使わずにC++で型安全に日付が扱えるようになる。



int main()
{
    using namespace std::chrono_literals;
    auto date = 2016y/may/29;
    cout << date << "\n";
    // 2016-05-29
}

便利だ。

[PDF] P0447R1: Introduction of std::colony to the standard library

flat_mapと同じくらい注目している新しいコンテナーの提案、colony。

colonyはvectorのような連続したストレージ上に構築される要素に順番の概念があるシーケンスコンテナーだが、中間要素への削除が定数時間ですむ。

どのように実装しているかというと、要素の数だけのビットマップを持っていて、それぞれの要素が有効かどうかの情報をビットマップで保持している。これにより、要素をずらす処理が必要なくなる。そして、中間への挿入も無効な要素がたまたまあれば定数時間で終わる。

これはほしい。

P0479R1: Attributes for Likely and Unlikely Statements

分岐先が実行されると期待できる場合と期待できない場合にその情報をコード中に記述できる属性、[[likely]]と[[unlikely]]の提案。


if ( is_unexpected_error() ) [[unlikely]]
{
    // まず発生しないエラーの処理
}

while( is_program_exit() )
[[likely]]{
// 終了することがほとんどないプログラムの処理
}

深いパイプラインを持つ近代的なプロセッサーでは、分岐予測を外した時のペナルティは大きい。もし、プログラム中のある分岐先がほとんど確実に実行される、あるいは実行されないことがコンパイル時にわかっている場合、プロセッサーによっては分岐予測にヒントを与える命令を使うことによって分岐命令のパフォーマンスを上げることができる。そのような情報をソースコードに付加するための属性。

if, while, do while, for, range-based forに記述できる。

既存の提案の改訂版を片付けた。あとは新しい提案のうち興味のあるものだけをさっと解説して参考書の執筆に戻りたい。

ドワンゴ広告

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

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

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

2017-02-09

高度に発展した特許業界はヤクザと見分けがつかない

Azure IP Advantage – intellectual property protection | Microsoft Azure

Microsoft AzureがAzure IP Advantageなるサービスを始めた。

特許ゴロによる大量のゴミ特許を抱えたうえでどれかに抵触しているだろうと当たりをつけて手当たりしだいに革新的な製品、サービスを提供しているものに訴訟を仕掛ける商売はいい儲けになっている。

そのような特許ゴロ訴訟に対抗する手段としては、こちらでも大量のゴミ特許を抱えておき、特許侵害を訴えられたら相手も自分のゴミ特許のどれかに抵触しているだろうとあたりとつけて特許侵害で逆提訴するというものだ。訴訟は技術を全くわかっていない弁護士と裁判官が何年も言葉遊びを弄した挙句、和解に終わるという泥仕合を繰り広げる。

といっても、そんなことができるのは大量の特許を保有できる資本力のある世界的に有名な大企業だけであり、大多数の実際に世界に技術革新を起こしている中小企業としては、訴訟の費用と特許利用料を天秤にかけると、訴訟をしないほうが安上がりになることが期待できるので、特許利用料を支払ったほうがマシという納得できない選択が最善の状態になってしまう。

今回Microsoftが始めた商売というのは、特許ゴロ訴訟を起こされた場合、Microsoftが大量に保有するパテント・プールをもって特許ゴロを叩くというものだ。

しかしこれは、何か見覚えのある商売のように思えてならない。

世の中にはヤクザと呼ばれる圧倒的な暴力を保有した複数の団体がいる。ヤクザは暴力を行使してあなたから金を巻き上げていく。あなたはヤクザの一つにみかじめ料を支払うことによって、他のヤクザの暴力に暴力で対抗して守ってもらう。

ヤクザを特許ゴロに、暴力を特許に置き換えるとどうだろうか。不思議なほどの一致を見るではないか。これでは特許ゴロとヤクザの見分けがつかない。ヤクザのような見た目でヤクザのように鳴くならばそれはヤクザである。

そして今回のタイトルに繋がる。「高度に発展した特許業界はヤクザと見分けがつかない」

ヤクザのシノギを作り出すだけで技術革新を阻害する特許制度は廃止すべきである。

2017-02-07

「目撃!ドキュンはドキュンをバカにし過ぎでひどくない」と妻は言った

「目撃!ドキュンはドキュンをバカにしすぎでひどくない?」と妻は言った。

僕はその言葉の解釈に数秒悩んだあと、おもわずこみ上げる笑いこらえるのに苦労した。

それは午前二時の真夜中のことであった。僕と妻は非常に腹を空かせていたが、あいにくと冷蔵庫にはごぼうと生姜とにんにくしかなかった。さすがの僕でも、ごぼうの生姜とにんにくの炒め物などという何の腹の足しにならない料理を妻に提案することはしなかった。我々が村上春樹の信奉者であれば、ここでパン屋を襲撃しに行かなければならないところだが、幸い我々は村上春樹がそれほど好きではなかった。

家のすぐ近くにはすき家があるが、我々夫婦はすき家に行くのは最終手段であると考えていた。というのも、夜中に寝巻き姿で夫婦揃ってすき家に行くのは、いかにもDQNのやることであり、文化的に生きる我々にははばかられる種類の行いであるように思われたからだ。

しかし腹は空いた。食べるものが家にない。コンビニにめぼしい物も売っていない。残念ながら、今夜は最終手段としてDQNに成り下がる必要がある。

我々夫婦は最低限の防寒具を着て、DQNのようにすき家に向かった。

「何、DQNの語源を知らないのかい?」

妻はDQNという言葉を知っている上によく使うにもかかわらず、DQNの語源を知らなかった。DQNとはドキュンと読み、かつての2ちゃんねるで使われていたネットスラングが定着した言葉である。今はDQNと書くことが多いが、当時はドキュンとかドキュソと書くほうが一般的だったはずだ。そもそもの語源は、昔「目撃!ドキュン」というテレビ番組があり、いかにも教養のない家庭環境に問題を抱えている下層階級の親子を放送していたので、そのような低俗な人間を指す言葉としてDQNが使われるようになったのであった。

「・・・そういうわけで、ドキュンは2ちゃんねるで使われていたスラングだけれど、もともとは目撃!ドキュンというテレビ番組が・・・」

「なにその番組名? ドキュンをバカにしすぎでひどくない?」と妻は言った。

僕はすき家の中で、おもわずこみ上げる笑いこらえるのに苦労した。

「それは逆だよ。目撃ドキュンという番組名が作られたとき、まだドキュンはオノマトペとしての意味しか持っていなかったんだ。」

言葉の変遷とは不思議なものだ。語源によって新たに創りだされた言葉の影響で語源の意味が変わってしまう。