2016-01-07

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

内容は以下で解説しているものの改訂版。

本の虫: C++標準化委員会の文書2015-09 pre-Konaのレビュー: P0001R0-P0009R0

本の虫: C++標準化委員会の文書 2015-09 pre-Kona: P0011R0-P0020R0

P0001R1: Remove Deprecated Use of the register Keyword

registerキーワードの廃止。変更点はCとの互換性の一覧に追加。ドラフト入りした。

P0002R1: Remove Deprecated operator++(bool)

operator ++(bool)の廃止。変更は文面上の些細な間違いの修正にとどまる。ドラフト入りした。

P0004R1: Remove Deprecated iostreams aliases

iostreamのdeprecatedされていたライブラリを廃止。変更は互換性の一覧に追加。ドラフト入りした。

P0005R1: Adopt 'not_fn' from Library Fundamentals 2 for C++17

汎用的なnot_fnの追加。変更点はネストされた型名result_typeの削除。理由はISO/IEC JTC1/SC22/WG21 p0090r0による。

P0005R2: Adopt 'not_fn' from Library Fundamentals 2 for C++17

not_fnのさらなる改訂版。result_typeの復活。

P0007R1: Constant View: A proposal for a 'std::as_const' helper function template

実引数をconstなlvalueリファレンスとして返すstd::add_const。変更点は文面案の追加。

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

namespace std
{
    template< typename T >
    inline typename std::add_const< T >::type &
    as_const( T &t ) noexcept
    {
        return t;
    }

}

P0012R1: Make exception-specifications be part of the type system, version 5

P0012R1: Make exception-specifications be part of the type system, version 5

関数の無例外指定を型システムに含める提案、関数ポインターに無例外指定を型として含めることができる。変更は些細。

P0013R1: Logical Operator Type Traits (revision 1)

boost MPLにあるand_, or_, not_の提案。ただし、生枝がことなる。

前回の提案は、and_, or_, not_だったが、今回の提案では、議論の結果、名前が変わっている。それぞれ、conjunction, disjunction, negationとなっている。

template < typename T, typename U >
void f()
{
    // std::is_same_v<T, U> && std::is_integral_v<T> && std::is_signed_v<T>
    // と同じ
    constexpr bool b = std::conjunction_v< std::is_same<T, U>, std::is_integral<T>, std::is_signed<T> > ;
}

negationはともかく、conjunctionとdisjunctionは英語を母語とせず、数学の素養もなく、コンピューターサイエンスのアカデミックの経歴もない筆者にはわかりにくい気がするのだが、いいのだろうか。

とはいえ、この関数は初心者が使うものでもないし、これでいいのかもしれない。

P0014R1: Proposal to add the multiline option to std::regex for its ECMAScript engine

regexにECMAScriptにあるmutlilineオプションを追加する提案。multilineオプションを使うと、^と&の挙動が変わり、文字列の戦闘と末尾ではなく、文字列の各業の戦闘と末尾にまっ地するようになる。

P0017R1: Extension to aggregate initialization

基本クラスを持つクラス型をアグリゲート初期化できるようにする提案。

基本クラスを持つクラスはアグリゲート初期化できない。

struct base { int x ; } ;
struct derived : base
{
    int y ;
} ;

// エラー、derivedは基本クラスを持つ
derived d{ 1, 2 } ;

これに対し、直接の基本クラスを宣言順で初期化できるようにしようという提案。

// {1}はbase::xの初期化,
derived d{ {1}, 2 } ;

P0018r1 : Lambda Capture of *this by Value

lambda式で*thisをコピーキャプチャする機能の提案。

lambda式では、thisでキャプチャするのはポインターである。メンバー名を使った場合、キャプチャしたthisポインターを経由したアクセスが行われる。

struct X
{
    int member ;

    auto f()
    {
        // this->memberと同じ
        return [=]() { return member ; }
    }
} ;

クラスのオブジェクトの寿命が尽きた後もクロージャーオブジェクトを使いたい場合に、問題になる。

int main()
{
    std::function< int () > f ;

    {
        X x ;
        f = x.f() ;
    }// xの寿命、ここまで

    f() ; // エラー、xはすでに破棄されている。
}

C++14では、明示的なキャプチャー機能が追加された。

struct X
{
    int member ;

    auto f()
    {
        // memberはコピーされる
        return [ =,  member = member ]() { return member ; }
    }
} ;

問題は、データメンバーが複数ある時、これをいちいち書くのは面倒だ。明示的なキャプチャーで、クラスのオブジェクト自体をキャプチャーすることはできる。

struct X
{
    int member ;

    auto f()
    {
        // memberはコピーされる
        return [ =, self = *this ]() { return self.member ; }
    }
} ;

しかし、この例では、thisポインターは依然としてキャプチャーされてしまう。もし、self.memberのかわりにmemberと書いてしまうと、this->memberとして扱われる。極めて危険で間違いの元だ。

そこで、新しいラムダキャプチャーに、*thisを追加する。ラムダキャプチャーに*thisと書くと、クラスのオブジェクトをコピーする。


struct X
{
    int member ;

    void f()
    {
        // this->memberと同じ
        [this]{ member ; }

        // *thisを値でコピーする。
        // memberはクロージャーオブジェクトにコピーされたオブジェクトを参照する。
        [*this]{ member ; }
    }
} ;

つまり、以下のようなクロージャーオブジェクトが生成されると考えればよい。


struct closure_object
{
    // *thisをコピーする
    X unnamed_copy ;

    void operator () ()
    {
        unnamed_copy.member ;
    }
} ;

これは欲しい機能だ。

ドワンゴ広告

正月明けで昼夜逆転してしまった睡眠サイクルを強引に修正しようとした結果、DST(ドワンゴ標準時)から-4時間ほどずれてしまった。午前中に出社し、夕方過ぎに帰宅するようになってしまった。

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

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

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

No comments: