2015-02-19

C++標準 2015-02 mid-meetingのレビュー: N4360-N4369

ISO/IEC JTC1/SC22/WG21 - Papers 2015の紹介を進めていく。

[PDF] N4360: Delayed Evaluation Parameters

遅延評価引数の提案。この提案は具体的な文法の提案にまでは踏み込んでいない。

遅延評価引数とは、呼び出し元が関数の実引数に渡した式がその場で評価されず、関数内で最初に値が使われた時に評価される機能である。

// とても遅い関数
int f() ; 

void g( int x )
{
    bool b ;
    std::cin >> b ;
    if ( b )
        std::cout << x << std::endl ;
    else
        std::cout << 0 << std::endl ;
}

int main()
{
    g( f() + 1 ) ;
}

関数fは、値を返すのに、とてつもない重い計算を行うものとする。しかし、その値は、入力次第によっては必要がないものである。関数gに引数として与える式の評価は、実際に使う必要があるときまで遅延させたい。

これを現行のC++でやろうとすると、関数オブジェクトを引数にとって関数呼び出しするようなコードになる。

// とても遅い関数
int f() ; 

template < typename LazyInt >
void g( LazyInt x )
{
    bool b ;
    std::cin >> b ;
    if ( b )
        std::cout << x() << std::endl ;
    else
        std::cout << 0 << std::endl ;
}

int main()
{
    g( [](){ return f() + 1 ; } ) ;
}

しかし、このようなコードを手で書くのは面倒だ。このような遅延評価引数機能をコア言語に追加してはどうか。

論文は設計方針として、いくつかの提案をしている。

引数はキャッシュ風に一度だけ評価されるべきか、インスタンス風にそのつど評価されるべきか - 一度だけ評価されるべき

引数はいつ評価されるべきか - 値が必要とされるとき。値へのポインターやリファレンスを取る場合も含む。sizeof, typeid, alignas, decltypeでは評価されない。

遅延評価引数がさらに別の遅延評価引数の中に入れられた場合はどうするか - 遅延評価引数は自動的に評価されるべきではない。

遅延評価引数はstd::functionのようにラッパーであるべきか、lambdaのように別のオブジェクトであるべきか - ラッパーのようであるべき

文法は?

三案ある。

  1. シンボル。これはシンボルは型の一部であるという既存の手法と異なる。
  2. lazyのような新しいキーワード。新しいキーワードは既存のコードを壊す恐れがある。既存の文法を折り合う文脈依存キーワードもない
  3. 既存のキーワードを再利用する。inlineがよさそうだ

規格準拠の実装は、観測可能な副作用がない場合、遅延評価引数をthunkを使わずに実行することができる。

[PDf] N4361: Concepts Lite TS

タイトル通り、Concept LiteのTSドラフト。

軽量コンセプトは、SFINAEに毛が生えたような設計になっている。

N4362: WG21 2015-01 Skillman Minutes

2015年1月26-27日にSkilmanで行われた会議の議事録。

[PDf] N4365: Responses to National Body Comments, ISO/IEC PDTS 19568, C++ Extensions for Library Fundamentals

Library Fundamentals TSに対するNBコメントへの回答。

日本からはmake_applyを追加すべきだというコメントを送ったが、合意がないとして却下された。提案論文を出せとのことだ。

N4366: LWG 2228: Missing SFINAE rule in unique_ptr templated assignment

unique_ptrのdeleterの型に互換性のない場合でも、オーバーロード解決の候補に上がってしまうことの修正。

以下のコードを修正する。

#include <memory>
#include <type_traits>

struct do_nothing
{
    template <class T>
    void operator()(T*) {}
};

int
main()
{
    int i = 0;
    std::unique_ptr<int, do_nothing> p1(&i);
    std::unique_ptr<int> p2;

    // OK
    static_assert(std::is_assignable<decltype(p2), decltype(p1)>::value, "");

    // コンパイルエラー
    p2 = std::move(p1);
}

なぜかというと、unique_ptrのムーブ代入演算子がオーバーロード解決の候補関数に上がらない条件(SFINAEで阻止される条件)が、デリーターを考慮していないからだ。デリーターを考慮するように規格を修正する提案。

N4367: Comparison in C++

比較関数の提案。

そもそも比較というのは様々ある。同値関係と順序とがあり、同値関係にはequivalenceとequalityがあり、順序には、partial ordering, weak ordering, total orderingが存在する。例えば、通常のソートにはweak orderingが必要で、メモ化にはweak orderingとequalityが必要だ。

三種類の異なる順序を、operator <ひとつで扱うという既存の仕組みがそもそも間違っていたのだ。そこで、これら三種類の順序比較をテンプレート関数として標準ライブラリに追加してはどうか。

template<typename T> bool partial_less(const T&,const T&);
template<typename T> bool weak_less(const T&,const T&);
template<typename T> bool total_less(const T&,const T&);

また、同値関係についても同様に追加してはどうか。

template<typename T> bool partial_unordered(const T&,const T&);
template<typename T> bool weak_equal(const T&,const T&);
template<typename T> bool total_equal(const T&,const T&);

また、strcmpのように、less, greater, neitherの三値を返す関数テンプレートを追加するべきではないか。三値はstrong enumで以下のように提供する。

enum class partial_ordering { less, unordered, greater };
enum class weak_ordering { less, equivalent, greater };
enum class total_ordering { less, equal, greater };

これに対応する関数テンプレートは以下の通り。

template<typename T> partial_ordering partial_order(T,T)
template<typename T> weak_ordering weak_order(T,T)
template<typename T> total_ordering total_order(T,T)

これにより、比較の結果と目的の比較方法を取り違える間違いは型安全に回避できる。

N4368: Introducing alias size_type for type size_t in class std::bitset

std::bitsetにネストされた型名であるsize_typeを追加する提案。

vector<bool>を利用している既存のコードをbitsetに移行する際に、よく使われる共通のネストされた型名が存在しないと既存のコードがうごかないため、その対応。

N4369: Default argument for second parameter of std::advance

C++11に追加されたstd::nextとstd::prevの第二引数には、デフォルト実引数として1が使われている。そのため、

auto it2 = std::next( it1, 1 ) ;

と書くかわりに、

auto it2 = std::next( it1 ) ;

と書くことができる。

std::advanceにも同等のデフォルト実引数があってもよいはずだ。

std::advance( ita, 1 ) ;

と書くかわりに、

std::advance( ita ) ;

と書くことが出来る。

ドワンゴ広告

サーバールーム兼野菜室というのは、冷蔵室にサーバーラックと野菜が詰め込まれているものかと想像したが、サーバーからの排熱を利用した温室だという説もあり、はっきりしない。

特定のグループに所属する人間専用のシェアハウスというのはすぐに平凡な日常に陥ると思うのだが、大丈夫なのだろうか。

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

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

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

1 comment:

Anonymous said...

比較関数の提案はいいとは思いますけど、なんか重たいですねぇ。処理がっていうより思考が・・・。
lazyは難しい問題ですねぇ。導入初期は難解なキーワードをプリプロセッサで置換して様子見るとかそういう逃げ道もありますけど。いまいちですねぇ。難しいです。素直にlazy追加するのが近道かもですねぇ。

鯖室兼野菜室というのは二酸化炭素が少なくてあんまり発育よくなさそうですね。
なんか秘策でもあるんですか?