本の虫

著者:江添亮
ブログ: http://cpplover.blogspot.jp/
メール: boostcpp@gmail.com
Twitter: https://twitter.com/EzoeRyou
GitHub: https://github.com/EzoeRyou

アマゾンの江添のほしい物リストを著者に送るとブログ記事のネタになる

筆者にブログのネタになる品物を直接送りたい場合、住所をメールで質問してください。

2018-04でC++のドラフトに入った変更

C++のドラフトが更新されている。最新版はN4741だ。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4741.pdf

変更点はEditor's Reportに書いてある。

N4740: N4740 Editors' Report -- Programming Languages -- C++

今回入った主要な変更は以下の通り。

P0840R2: Language support for empty objects

[[no_unique_address]]属性の追加。

この属性は、クラスが状態を持たずクラスを表現するためにストレージを割り当てなくてもよいことを意味する。

クラスには、存在すること自体に意味があり、そのオブジェクトに特に意味はないクラスがある。


template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  Hash hasher;
  Pred pred;
  Allocator alloc;
  // ...
public:
  // ...
};

このようなコードで、HashやPredやAllocatorといったクラスが状態を持たないもののみを使用可能だと取り決めた場合、ストレージを割り当てる必要がない。しかし、このような基本クラスや非staticデータメンバーであっても、アドレス可能にするために最低でも1バイトはストレージを割り当てる必要がある。

[[no_unique_address]]はこのようなストレージの確保を必要としない、アドレスを取る必要がない型に使うことで、不必要なストレージの割当を回避することができる。


template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  [[no_unique_address]] Hash hasher;
  [[no_unique_address]] Pred pred;
  [[no_unique_address]] Allocator alloc;
  // ...
public:
  // ...
};

P0962R1: Relaxing the range-for loop customization point finding rules

range-based forはメンバー関数begin/endのいずれか片方を持っている場合は、ADLによるbegin/endの検索を行わない。しかし、たまたまクラスがbegin/endという名前の片方のメンバー関数だけを持っていた場合も、ADLによる検索が行われない。

range-base forはbegin/end両方のメンバー関数を持つ場合のみADLによる検索を行わないようにする変更。

当然の話だ。

[PDF] P0969R0: Allow structured bindings to accessible members

クラスを構造化束縛する場合、メンバーはpublicでなければならないとされている。


class Three
{
    int a, b, c ;
} ;

void f()
{
    Three t{1,2,3} ;
    auto [a,b,c] = t ; // エラー
}

しかしこれはおかしな話だ。というのも、アクセス指定というのは使った文脈が重要だからだ。


class Three
{
    int a, b, c ;
    friend void f() ;
public :
    Three( int a, int b, int c )
        : a(a), b(b), c(c) { }
} ;

void f()
{
    Three t{1,2,3} ;
    // エラー、friendなのに
    auto [a,b,c] = t ; 
}

構造化束縛でpublicなメンバーに限らず、アクセスできる場所ではアクセスできるようにする変更。

当然すぎる。

P0961R1: Relaxing the structured bindings customization point finding rules

構造化束縛でメンバー関数getが見つかったときに、テンプレートではない場合は、ADLで検索する機能。

これも当然だ。

P0634R3: Down with typename!

文脈上型であることが明らかな場所では依存名にtypenameを付けなくても良くする機能。

template < typename T >
using type = typename T::type ;

と書くかわりに、

template < typename T >
using type = T::type ;

と書ける。他にも様々な文脈上型しか書けない場所でtypenameを省略できる。

P0780R2: Pack expansion in lambda init-capture

ラムダ式の初期化キャプチャーの中でパック展開できる機能。

たとえば、パラメーターパックをstd::moveしつつパック展開して初期化キャプチャーするには以下のように書ける。

template < typename ... Types  >
void f( Types & ... args )
{
    [ ... args = std::move(args) ]
    (){ } ;
}

P0479R5: Proposed wording for likely and unlikely attributes (Revision 5)

分岐先の実行されやすさを指示できる[[likely]], [[unlikely]]属性の追加。

ある分岐先が実行されやすい時、あるいは実行されにくいときがコンパイル時にわかっているときは、その情報をコンパイラーにヒントとして伝えることで、コンパイラーは実行されやすいコードをよりキャッシュに乗りやすいホットな領域に配置したり、コード生成を工夫したりといった最適化ができる。


// めったに起こらないエラーの確認
if ( check_uncommon_error() )
{
    [[unlikely]] ;
    // エラー時の処理
}

// 必ず成功するはずの初歩的なチェック
if ( sanity_check() )
{
    [[likely] ;
    // 通常の処理
}

P0905R1: Symmetry for spaceship

比較演算子としてoperator <=>が追加されたが、"a <=> b"が合法であるならば、"b <=> a"も合法であり、かつその結果も自然なものになるように規定する変更。

[PDF] P0754R2: version

何もしないヘッダーファイル<version>の追加。このヘッダーファイルはコンパイラーによって定義される実装依存の定義済みマクロなどを定義ささせるのに使われる。そのような定義済みマクロを使うには、何らかの標準ヘッダーを#includeしなければならず、そのような軽量ヘッダーとして追加された。

P0355R7: Extending to Calendars and Time Zones

<chrono>にカレンダー機能を追加する。ユーザー定義リテラルによりコード中でも読みやすくなる。

int main()
{
    auto date = 2018y/April/18 ;

    // 2018-04-18
    std::cout << date << "\n" ;

    // 2018-04-19
    date += 1 ;
    std::cout << date << "\n" ;
    
    // 2018-03-25
    date -= 25 ;
    std::cout << date << "\n" ;
    
}

日付処理が簡単にできるようになる。

[PDF] P0122R7: span : bounds - safe views for sequences of objects

spanライブラリの追加。これは連続したストレージ上の配列を扱うストレージを所有しないライブラリだ。