2016-06-29

C++標準化委員会の文書: P0250R0-P0259R0

P0250R1: Wording improvements for initialization and thread ids (CWG 2046)

実行単位と実行順序についての文面や言葉の使い分けを微妙に変える提案。

標準化委員会の中では、C++は将来的に、プログラムが明示的にスレッドを使っていなかったとしても、実装が自動的に初期化を並列実行することを許可したいコンセンサスがあるが、現行の文面も既存のコードもそのまま対応できるようにはなっていない。とりあえず文面を整理する。

[PDF] P0251R0: Unified Call Syntax Wording

統一関数呼び出し記法の提案。

f( x, y )という式を書いた時に、f( x, y )を満たすfが存在しない場合、x.f( y )を呼び出す機能のことだ。

template < typename T >
void f( T x, T y )
{
    compare( x, y ) ;
}

この例では、もしcompare( x, y )を満たすcompareが存在しない場合、x.compare( y )の呼び出しが試みられる。

当初の提案に上がっていた、x.f(y)をf(x,y)として扱う機能は省かれた。

これにより、ジェネリックコードは渡された型について気にする必要がなくなる。

[PDF] P0252R1: Operator Dot Wording

operator .をオーバーロード可能にする提案。operator .をオーバーロードした型に対するメンバーアクセスは、原則としてoperator .の戻り値に対して適用される。型に同じ名前のメンバー名がある場合を除く。

template < typename T >
class vector_ref
{
    std::vector<T> v ;
public :
    std::vector<T> & operator .() { return v ;}
    std::vector<T> const  & operator .() const { return v ;}

    std::size_t size() const { return 1 ; }
} ;

int main()
{
    vector_ref r ;

    // operator .を経由した
    // vector_ref.vに対する操作
    r.push_back(0) ;

    // vector_ref.sizeを呼ぶ
    r.size() ;
}

これにより、スマートリファレンスを実装することが可能になる。

operator .はクラス型から、リファレンス型を返すことができる。operator .をオーバーロードした型を、リファレンスサロゲート型と呼ぶ。複数のoperator .が記述されている場合、メンバー名によるオーバーロード解決が行われる。

struct A
{
    int x ;
} ;

struct B
{
    int y ;
}

struct C 
{
    A a ;
    B b ;
    A & operator .() { return a ; } 
    B & operator .() { return b ; }
} ;

int main()
{
    C c{ } ;

    c.x = 0 ; // c.a.x
    c.y = 0 ; // c.b.y
}

名前が衝突した場合は曖昧なためill-formedになる。

struct A
{
    int x ;
} ;

struct B
{
    int x ;
}

struct C 
{
    A a ;
    B b ;
    A & operator .() { return a ; } 
    B & operator .() { return b ; }
} ;

int main()
{
    C c{ } ;

    c.x = 0 ; // エラー、曖昧
}

リファレンスサロゲート型によって初期化した場合、オーバーロード解決により最適なoperator .が選ばれる

struct X
{
    int i ;
    double d ;

    int & operator . () { return i ; }
    double & operator . () { return d ; }
} ;

このようなリファレンスサロゲート型に対して、

以下はwell-formedとなる。

X x{ 0, 0.0 } ;
int i = x ; // well-formed
double d = x ; // well-formed

リファレンスサロゲート型に対する代入には、そのようなオーバーロード解決が働かず、operator .も使っていないため、以下はill-formedとなるのか、それともコピー代入演算子の呼び出しもoperator .を使うからwell-formedなのか、よくわからない。


X x{ 0, 0.0 } ;
x = 0 ; // 謎
x = 0.0 ; // 謎

また、operator .と変換関数がある場合、変換関数が優先されるのではないかと思われる。

struct X
{
    int i ;
    int & operator . () { return i ; }
    operator int & () { return i ; }
} ;

X x{0} ;
int i = x ; // call conversion function

と、このようないろいろな疑問を論文著者に聞いてみたところ、実際オーバーロード解決についてあやふやなため、いま開催中のOulu会議で文書自体が却下されたらしい。

[PDF] P0253R1: Fixing a design mistake in the searchers interface in Library Fundamentals

BMサーチなどを実装するために設計されたsearcherの戻り値を、パターンにマッチした先頭へのイテレーターを返すのではなく、マッチしたパターンの先頭と末尾のイテレーターのpairを返すようにする提案。

次のパターンを探したいことがよくあるから最適化のため。

[PDF] P0254R1: Integrating std::string_view and std::string

stringからstring_viewへの変換は、stringの変換関数が担うべきであるため、そのように設計を変更する提案。

[PDF] P0255R0: C++ Static Reflection via template pack expansion

テンプレートのパック展開を用いた静的リフレクション。使いたくないほど文法が汚い。1

[PDF] P0256R0: C++ Reflection Light

現在提案されているC++の静的リフレクション機能を比較して考察している。

T型のデータメンバーのポインターを取得する

N4428提案

int size = std::class_traits<T>::class_members::size;
// テンプレートメタプログラミングにより0からsize-1までのそれぞれのIについて取得する
auto pointer = std::class_traits<C>::class_members::ge<I>::pointer;
// その後、pointerの型をそれぞれ調べて、データメンバーのみを抽出する処理が必要

P0194R0提案

typedef reflexpr(T) meta_T;
typedef std::meta::get_all_data_members_t<meta_T> meta_DMs;
int size = std::meta::get_size_v<meta_DMs>; // get number of data members
// apply template meta to recurrently pick each I, from 0 to size - 1
// テンプレートメタプログラミングにより、0からsize-1までのそれぞれのIについて取得する
typedef std::meta::get_element_t<meta_DMs, I> meta_F;
gauto pointer = std::meta::get_pointer_v<meta_F>;

P0255R0提案

auto pointers = std::make_tuple( typedef< T, is_member_object_pointer >... );

お題:プライベート・ライアンは救えるか?

struct X {
private:
    int ryan;
};

Urbana会議の結論として、privateメンバーにはうっかりアクセスできないようにしたい。既存のコードにアクセス性を与えるような変更ができないようにしたい。reflection_unsafeのように明示的な操作を必要とするようにすべきか。

[PDF] P0257R1: A byte type for increased type safety

1バイトを表現するstd::byte型を標準ライブラリに追加する提案。

現在、1バイトを表現するには、char, signed char, unsigned charが使われているが、char型には、バイト単位のアクセス、数値型、文字型という3つの目的が割り当てられており、混同しやすい。そのため、バイト単位のアクセス専門の型が必要だ。

std::byteは以下のようにscoped enumで定義されている。


namespace std {
    enum class byte : unsigned char { } ;
}

わざわざコア言語に新しいキーワードとして組み込むまでもなく、既存の言語機能だけで実現できるとしている。

また、コア言語に手を加えて、今までのvoid *からchar *に加えて、std::byte *にstatic_castした場合でもバイト単位でのアクセスが保証される。

P0258R1: is_contiguous_layout

is_contiguous_layout traitsの追加。型がstandard layout typeかつ、すべてのビットがオブジェクトの値の表現に使われる場合にtrueを返す。

例えば、パディングビットが存在するような型に対してはfalseが返される。

目的は、バイト列からハッシュ計算をする最適化ができる型かどうか判定するためだ。

[PDF] P0259R0: fixed_string: a compile-time string

constexpr実装できるbasic_fixed_stringの提案。

basic_stringはconstexpr実装できないので、コンパイル時に文字列処理をするためにconstexpr実装できる設計の文字列クラスを追加する。

constexpr auto hello = std::make_fixed_string("hello") ;
constexpr auto world = std::make_fixed_string("world") ;

constexpr auto helloworld = hello + ", " + world ;

static_assert( helloworld == "hello, world" ) ;

ドワンゴ広告

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

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

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

3 comments:

Anonymous said...

のぉ~。ユニファイドコールシンタックスからほしい機能が省かれた・・・。
お、おれの黒魔術が・・・。Orz

Anonymous said...

別にどっちかさえできれば黒魔術は使えるのでは?
ちょっと面倒なだけで……。

Anonymous said...

言われてみてできなことも無いですけど、見た目が気に入らないですね。
チェインしたい!