2016-04-01

C++標準化委員会の文書: P0200R0-P0209R0

P0200R0: A Proposal to Add Y Combinator to the Standard Library

lambda式で再帰できるようにするY Combinbatorライブラリの提案。

int main()
{
    auto gcd = std:y_combinator( []( auto gcd, int a, int b ) -> int
        {
            return b == 0 ? a : gcd( b, a % b ) ;
        } ) ;

    std::cout << gcd( 20, 30 ) << std::endl ;
}

実装例

template < typename Fun >
class y_combinator_result
{
    Fun f ;
public :
    template < typename T >
    explicit y_combinator_result( T && fun )
        : f( std::forward<T>(fun) )
    { }

    template < typename ... Args >
    decltype(auto)
    operator () ( Args && ... args )
    {
        return f( std::ref(*this), std::forward<Args>(args)... ) ;
    }
} ;

template < typename Fun >
y_combinator_result<std::decay_t<Fun>> y_combinator( Fun && fun )
{
    return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun)) ;
}

[PDF] O0201R0: A cloning pointer-class for C++

コピー時にポインターの参照先をディープコピーするclone_ptrの提案。

int main()
{
    auto p1 = std::make_clone_ptr<int>(42) ;
    auto p2 = p1 ;
}

これは、以下のようなコードと同じ意味になる。

int * p1 = new int( 42 ) ;
int * p2 = new int( *p1 ) ;
delete p2 ;
delete p1 ;

また、clone_ptrは初期化時に渡されたmost derived typeによるポリモーフィックな型のディープコピーや破棄が正しく行える。


struct Base
{
    virtual void f() = 0 ;
    ~Base() { } // virtualデストラクターではない
} ;
struct Derived
{
    void f() override { }
    Derived() { }
} ;

// 実行時型
clone_ptr<Base> p1( new Derived() ) ;
auto p2 = p1 ;

// ディープコピーが行われる
assert( p1.get() != p2.get() ) ;
// Baseではなく実行時の型であるDerivedとしてコピーが行われる
assert( dynamic_cast< Derived * >(p2.get() != nullptr )

// p1, p2の破棄では、Derivedのデストラクターが呼ばれる

shared_ptrと同じだ。

コピー時にディープコピーを行うクラスのデータメンバーとして生のポインターの代わりに安全に使えるので入るべきだ。

A Proposal to Add Constexpr Modifiers to Functions in <algorithm> and <cstring> Headers

<algorithm>と<cstring>をconstexpr対応にする提案。イテレーターのconstexpr化は別の提案で行う。

<algorithm>をconstexpr化する提案。多くのアルゴリズムは<cstring>に依存しているので、<cstring>もconstexpr化する。

std::memcpyやstd::memmoveは、void *型の引数を取るので、本来constexpr化できないのだが、constexpr化しないとライブラリ実装はcompiler intrinsicsを使うだけなので、constexpr化する。

P0203R0: Considerations for the design of expressive portable SIMD vectors

SIMD型の提供に関する考察。

P0205R0: Allow Seeding Random Number Engines with std::random_device

乱数エンジンをrandom_deviceで初期化できるようにする提案。

現状では、random_deviceからビット列を手動で取り出して乱数エンジンに食わせてやらなければならないが、乱数エンジンの内部状態が何ビットなのか得る方法がないため、適切な初期化が移植性の高い方法で書けない。

これは当然入るべきだし、そもそも最初から入っているべき機能だ。

P0206R0: Discussion about std::thread and RAII

threadのデストラクターが実装された時に、threadがjoinableであると、terminateが呼ばれる。これは様々な問題を引き起こす。しかし一方で、この挙動のほうが好ましい場合もある。

この文書は、threadのデストラクターは自動的にjoinを呼ぶ変更か、自動的にjoinを呼ぶ別のthread型を追加する文面案を提示している。

既存のコードの挙動を変えないために別の型にすべきだろう。

P0207R0: Ruminations on lambda captures

lambada式で値によるデフォルトキャプチャー[=]が使われた場合、クラスのメンバーはthisポインター経由ではなく、値によるキャプチャーになるように挙動を変更するとどうなるかを考察。

この文書は、既存の挙動は変えないことを推奨している。

筆者は変えるべきだと思う。

[PDF] P0208R0: Copy-Swap Helper

強い例外安全を実現するために、まずオブジェクトをコピーして改変し、改変が例外を投げなければswapする。改変が例外を投げた場合元のオブジェクトは変更されないという処理を行うヘルパー関数の追加。

文面案のcopy_swap_helperの宣言が間違っている気がする。

[PDF] P0209R0: make_from_tuple: apply for construction

tupleの各要素をコンストラクターに渡してオブジェクトを構築してくれるmake_from_tupleの提案。

以下のように使う。

struct X
{
    X( int, double, std::string ) ;
} ;

auto t = std::make_tuple( 1, 2.0, std::string("3") ) ;

auto x = std::make_from_tuple<X>( t ) ;
// 以下と同じ
// auto x = X( get<0>(t), get<1>(t), get<2>(t) ) ;

すでにtupleの各要素を関数の引数に渡してくれるapplyがあるが、

void f( int, double, std::string ) ;

std::apply( t, f ) ;

make_from_tupleはそのオブジェクト構築版と言える。

同様にして、placement newしてくれるuninitialized_construct_from_tupleがある。

alignas(X) char buf[sizeof(X)] ;
X * ptr = std::uninitialized_construct_from_tuple<X>( buf, t ) ;

実装は以下のようになる。

template < typename T, typename Tuple, std::size_t ... I >
T make_from_tuple_impl( Tuple && tuple, std::index_sequence<I ... >  )
{
    return T( std::get<I>( std::forward<Tuple>(tuple) )... ) ;
} ;

template < typename T, typename Tuple >
T make_from_tuple( Tuple && tuple )
{
    return make_from_tuple_impl<T>(
        std::forward<Tuple>(tuple),
        std::make_index_sequence<
            std::tuple_size_v< std::decay_t<Tuple> >
            >()
        ) ;
}

ドワンゴ広告

Ubuntu On Windowsでドワンゴ社内の支給PCの勢力図が塗り替えられそうな気がするが、いい加減に支給PCのWindowsぐらい最新にするべきだと思うしGNU/LinuxをOSの候補に加えるべきだ。

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

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

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

1 comment:

Anonymous said...

ラムダは現状でも参照キャプチャすれば再帰関数化できたと思いますが、シンプルキャプチャの時出来ないからってことなのですかね。
アルゴリズムヘッダーのconstexpr化は時代の流れから言って必須。疑いようもないです。
random_deviceはタイプするのが面倒なので結局乱数は0で初期化しています。大元的にやっつけてしまいます。
thereadは現在走ってるかどうか位取れるようにならんのですかね。もしくはアンブロック型joinとか。スレッドを大量に立て捨てしたい時にすごい不便です。
ラムダが=キャプチャしたときにはthisのポインタ値をキャプチャしてほしいです。値をコピーしたければ[x=(*this)]と書くべきです。シンプルキャプチャの枠をもうちょっと練るべきかもしれません。ほとんどの場合ライフサイクルは短いはずですからさほど問題にはならないはずです。