2014-08-29

2014-07 post Rapperswil mailingのレビュー: N4070-N4079

またもや次の論文10本

N4070: Improving the specification of the vector execution policy in Parallelism TS

Parallel TSのベクトル実行アルゴリズム内で実行される関数が同期をすることは禁止されている。しかし、標準ライブラリの関数のうち、同期を行わない保証のある関数なのかということは、明記していない。

これを解決するために手始めにそのことを警告する文面を追加する提案。

N4071: Technical Specification for C++ Extensions for Parallelism, Working Draft

C++のアルゴリズムに並列実行と並列ベクトル実行版のオーバーロードを追加して拡張するTSのドラフト。

従来のアルゴリズムに、タグを指定することで、シーケンシャル実行、並列実行、並列ベクトル実行を切り替えることができる。

// N4071提案
#include <experimental/execution_policy>
#include <experimental/algorithm>

template < typename Iterator >
void f( Iterator first, Iterator last )
{
// シーケンシャル実行
    std::stable_sort( std::seq, first, last ) ;

// 並列実行
    std::stable_sort( std::par, first, last ) ;

// 並列ベクトル実行
    std::stable_sort( std::par_vec, first, last ) ;
}

N4072: Fixed Size Parameter Packs

パラメーターパックの個数を指定できる機能、固定数パラメーターパックの提案。

// N4072提案

// argsは個数3、型はint型
void f( int ...[3] args ) ;

// argsの個数は3
template < typename ... Types >
void g( Types ... [3] args ) ;

// Argsの個数は3
template < typename ...[3] Args >
void h( Args ... args ) ;

T ...[N] pは、N個のT型のパラメーターパックpである。Nは定数式でなければならない。

いったいこの機能何に使うのか。論文では、いくつかの利用例を挙げている。

指定した個数の実引数を取りたい場合を考える。

struct my_vector3 {
    // ...
    my_vector3(int x, int y, int z)
        : values{x, y, z} {}
};

こんなクラスがあるとする。my_vector4とかmy_vector10などを手で書くのではなく、my_vector<N>のように、テンプレートで個数を指定したい。

実は、これは現行のC++14の枠内で行うのは、とてつもなく面倒で長ったらしいコードを書かなければならない。しかし、固定数パラメーターパックがあれば、以下のようにあっさりと書ける。


template<unsigned int N>
struct my_vector {
    // ...
    my_vector(int...[N] v) : values{v...} {}
};

指定した個数のある型の引数を取りたい。

void foo3( int, int, int )のような関数があるとする。ここで、foo4のような関数を手で書くのではなく、foo<N>のように、テンプレートで個数を指定したい。

しかし、これをC++14で簡潔に書く方法がない。固定数パラメーターパックならば、以下のように簡潔に書ける。


template<unsigned int N>
void foo(int...[N] v);

あるいは、単に機械的なパターンを手で書く代わりに使うこともできる。


void foo(int x, int y, int z, int w) { do_magic(x, y, z, w); }

template<typename A, typename B, typename C, typename D, typename E>
void bar(A a, B b, C c, D d, E e);

のような機械的なパターンのあるコードは、


void foo(int...[4] v) { do_magic(v...); }

template<typename...[5] T>
void bar(T... v);

このように書くことができる。

この提案では、実引数推定で、固定数を推定することができる。

例えば、以下のような例は実引数推定できる。

template < unsigned int N >
void f( int ... [N] ) { }

f( 1, 2, 3 ) ; // Nは3と推定される

template<unsigned int N> void f(int, int...[N]) {}
f(1,2,3); // Nは2と推定される

template<unsigned int N, unsigned int M> void f(int...[N], int...[M]) {}
f<2>(1,2,3); // Mは1と推定される。Nは推定できないが、明示的に指定されている

例えば、以下のような場合は、固定数パラメーターパックで実引数推定できない。


template<unsigned int N> void f(int...[N], int) {}
f(1,2,3);

template<unsigned int N> void f(int...[N], int...[N]) {}
f(1,2,1,2);

template<unsigned int N> void f(int...[N*2]) {}
f(1,2,3,4);

[暗い未来を予感させるPDF] N4073: A Proposal to Add 2D Graphics Rendering and Display to C++

C++の標準ライブラリグラフィックライブラリを追加することに対する考察と提案。cairoに機械的な変換を書けてC++風の設計にしている。

[Let PDF-writer die in agony] N4074: Let return {expr} Be Explicit, Revision 2

return {expr}の意味を、return-type var {expr} ; return var ;と同じ意味にしようという提案。

以下のようなコードを考える。

struct very_long_type_name
{
    explicit very_long_type_name(int) { }
} ;

very_long_type_name f()
{
    return { 0 } ; // ill-formed 
}

このコードを合法にする提案だ。

return文のオペランドを{}で囲んだ場合、戻り値の型のローカル変数を直接初期化して返すのと同等の効果にしようという提案である。

関数の戻り値の型と、その関数内のreturn文とは、関数の中だけの話だから、十分に明示的である。{}で囲むというのも明示的である。

very_long_type_name f()
{
    return very_long_type_name{0} ;
}

これはいかにも冗長だ。

[無駄にPDF] N4075: Centralized Defensive-Programming Support for Narrow Contracts (Revision 5)

防衛的プログラミングと称し、assertマクロの高級版を追加する提案。

assertに引っかかった時の挙動を指定できたり、テストできたりと、色々と高機能だが、Cプリプロセッサーマクロを使うという時点で、筆者は反対する。

N4076: A proposal to add a generalized callable negator (Revision 4)

汎用的なnegator、not_fnの提案。

not1やnot2は引数がひとつか二つのとても制約の強い関数オブジェクトしからっぷできなかった。not_fnは、Variadic Templatesや最近のメタプログラミング技法を使い、任意個の引数を取る任意の呼び出し可能なオブジェクトをラップできる。

// N4076提案
auto f() { return true ; }

int main()
{
    auto n =  std::not_fn(f) ;
    n() ; // false
}

N4077: Experimental shared_ptr for Library Fundamentals TS

TSに提案されるライブラリが使うために、実験的なshared_ptr実装である<experimental/memory>と、独立したshared_ptr, weak_ptr, owner_less, enable_shared_from_thisの提案。

詳しい経緯はN4041にかかれているが、TS用の拡張として既存の標準ライブラリを使う場合、サードパーティによる規格準拠の実装が作れないという問題がある。そこで、規格準拠な実験的実装を行えるように、必要な標準ライブラリを、同一機能であるが、別ヘッダー、別名前空間の別ライブラリとして定義する提案。

N4078: Fixes for optional objects

Issaquah会議で指摘された、Optionalのドラフト文面に存在する問題の修正。どれも小粒な文面上の修正となっている。

N4079: C++ Standard Library Issues Resolved Directly In Rapperswil, 2014

rapperswil会議で修正された標準ライブラリに持ち上がっている問題集。

些細な文面上の誤りの修正が多い。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日は都合で、いつもとは違い丸ノ内線に乗って通勤したが、明らかに周囲の背広集団から浮いている変わった服装と目立つ話し方をする人間を見かけた。銀座駅で降りて会社に向かったが、エレベーターの中で再開した。みると、ドワンゴの社員証を首から下げている。

さては同僚であったのか。

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

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

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

12 comments:

Anonymous said...

毎度お世話になります。
さっさと並列版アルゴリズムが入ってほしいです。
それと、固定長引数パックは、配列のシンタックスシュガーというか、コンストラクタ起動式で起動できればいいので特に可変長引数を弄って作るほどの価値があるようには見えません。
bool f(int N[4]){ return true;}
bool f2(int[4] N){ return false; }//いい加減このように引数を書きたい。
int main(){ f({ 1, 2, 3, 4 });}
と、いう風に書ければ満足してくれないでしょうかね??
それとN4074もいいですね。

Anonymous said...

あぁ、それともう一つ。
省略の美学もいいですけど、時間とともに意味が風化してしまうのであんまり省略ばかりするのはやめてほしいです。
最近は補完エディタも数多くありますしさほど問題にはならないはずです。

mmYYmmdd said...

固定長引数パックと無関係かもしれませんが、タイミングが良かったので
質問させてください。
「取りうるテンプレートパラメータの数」を取得することって出来ますか?
http://melpon.org/wandbox/permlink/cqO5NBN1mDkHG2uF
に書いたcount関数がそれです。
count => test2 => test1 と呼び出していて
最後の test1 は手で variadic 展開(?)しています。

Anonymous said...

こういうことですか?このブログで知りましたが。

#include

template
int F(T... A){
return sizeof...(A);
}

int main(){
std::cout << F(1, 2, 3, 4) << std::endl;

return 0;
}

Anonymous said...

テンプレート宣言とiostreamがきえちゃった。><;

Anonymous said...

あ、違いましたか。結構難しいですね。
テンプレート内テンプレートの公開範囲がうまく規定されてなくて取得できないんじゃないかと思います。
テンプレート内テンプレートのテンプレートパラメータを減らす方法がよくわからないので減算処理は多分できません。なので加算対応になってるかと思います。空間が閉鎖してるんですよね。
すふぃね検索中に自作クラスに差し替えとかできれば取れるかと思ったのですが。
テンプレート変数はすふぃねに使えるんでしょうか。使ったことないですけど初見の感想ではis_base_of_vはただのBOOL型では?話としては関数をすふぃねに使えるかということになるかと思います。

お役に立てなくて申し訳ない。
VCでは未来の話は辛いです。
インテリセンスは誤魔化せるんですけどコンパイラさん強いです。

mmYYmmdd said...

>減算処理は多分できません。
そうなんですよね。
再帰的に減らしていこうにも、(ソース12行目にコメントしたように)その対象であるFを与えてないからダメなんですよね。

>is_base_of_vはただのBOOL型では?
そう思って、
template bool B>
constexpr std::size_t count();
なんて構文をトライしたけどシンタックスエラーでした。

mmYYmmdd said...

あれ、?消えちゃうな。

templatebool B>
constexpr std::size_t count();
なんて構文をトライしたけどシンタックスエラーでした。

mmYYmmdd said...

template &lttemplate &lttypename...&gt bool B&gt
constexpr std::size_t count();
なんて構文をトライしたけどシンタックスエラーでした。

Anonymous said...

人んちのブログだけど、ドンマイと猛々しく叫ぶ!

変数テンプレートの文脈って多分関数テンプレートと同じ文脈だと思うんですよね。
SFINAEとして関数テンプレートが使えないなら無理だと思います。

mmYYmmdd said...

こうか。
template <template <typename...> bool B>
constexpr std::size_t count();

ところで関数テンプレートをSFI姐に使うって、疑似コードみたいなものありますか?
いまいちイメージできないので。

Anonymous said...

普段からSFINAEはあまり使ってないので自分もわからないです。
お役には立てないです。Orz