本の虫

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

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

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

C++1zに採択された新機能

C++1zともC++17とも呼ばれているC++の次の規格には、まだ大きな機能は採択されていない。それでも、いくつかドラフト入りしている新機能はあるので、ここではその機能を紹介していく。

いつも通り、ここに書かれている内容はまだドラフト段階の機能であり、今後変更されたり、取り除かれたりする可能性もある。

N3928: メッセージ無しstatic_assert

C++11で追加されたstatic_assertには、文法上、必ず文字列リテラルを記述しなければならなかった。

static_assert( expr, "Captain Obvious To the Rescue! expr is false.") ;

この文字列リテラルは、実装が診断メッセージ(例えばコンパイラーのエラーメッセージ)に使うことができる。しかし、C++14までは、文字列リテラルが文法上必須で、必ず記述しなければならなかった。

そこで、文字列リテラルを記述しなくても良い文法が追加された。

static_assert( expr ) ;

N4086: トライグラフの除去??!

トライグラフが文面から削除された。

N4051: テンプレートテンプレートパラメーターにtypenameキーワード

C++14まで、テンプレートテンプレートパラメーターの文法は、classキーワードしか使えなかった。

template < 
    template < typename T >
    class U // typenameキーワードは不可
> struct X ;

typenameも使えるようになる。

template < 
    template < typename T >
    typename U // typenameキーワードが使える
> struct X ;

N4295: Fold式

パラメーターパックの中身すべてに対して演算子を適用したい場合、再帰的なテンプレートを書く必要がある。例えば、引数をすべてoperator +で合計する関数テンプレートを書くと、以下のようになる。

template < typename T >
T sum( T && t )
{
    return t ;
} 

template < typename T, typename ... Types >
T sum( T && t, Types && ... args )
{
    return t + sum( std::forward<Types>( args ) ... ) ;
}

いかにも面倒だ。やりたいことは、a1 + a2 + a3 + ... + aNということなのに、この記述はあまりにも冗長すぎる。

そこで提案されているのが、fold式だ。パラメーターパックpにたいして、(p + ...)と書くと、p1 + p2 + p3 + ... pNとパック展開してくれる。

fold式を使うと、以下のように書ける。

template < typename ... Types  >
auto sum( Types && ... args )
{
    return (args + ...) ;
}

fold式では、括弧は必須である。

template < typename ... Types  >
auto sum( Types && ... args )
{
    // エラー
    return args + ... ;
}

fold式には、left foldとright foldが存在する。

(... op e)は、left foldである。(e1 op e2) op e3) op e4のように展開される。

template < typename ... Types  >
auto sum( Types && ... args )
{
    return (... + args) ;
}

int main()
{
    // ((1 + 2) + 3) + 4
    sum( 1, 2, 3, 4 ) ;
}

(e op ...)は、right foldである。e1 + (e2 + (e3 op e4))のように展開される。

template < typename ... Types  >
auto sum( Types && ... args )
{
    return ( args + ... ) ;
}

int main()
{
    // 1 + ( 2 + ( 3 + 4 ) )
    sum( 1, 2, 3, 4 ) ;
}

fold式には、単項fold(unary fold)と二項fold(binary fold)が存在する。

上記の、(... op e)と(e op ...)は、単項fold式である。

二項fold式とは、(e1 op1 ... op2 e2)のことである。op1とop2は同じfold演算子でなければならず、e1とe2のどちらか片方のみが未展開のパラメーターパックでなければならない。

e2がパラメーターパックである場合、left foldになる。e1がパラメーターパックの場合、right foldになる。

template < typename ... Types >
void sum( Types && ... args )
{
    // binary left fold
    auto a = ( 0 + ... + args ) ;
    // binary right fold
    auto b = ( args + ... + 0 ) ;

    // エラー、両方がパラメーターパック
    auto c = ( args + ... + args ) ;
    // エラー、両方が非パラメーターパック
    auto d = ( 0 + ... + 0 ) ;
}

fold式に使える演算子はfold演算子である。これは以下の通り。

    +  -  *  /  %  ^  &  |  =  <  >  <<  >>
    +=  -=  *=  /=  %=  ^=  &=  |=  <<=  >>=
    ==  !=  <=  >=  &&  ||  ,  .*  ->*

パラメーターパックが空の場合、一部のfold演算子については、以下のようにデフォルトの値が定められている。

Table N. Value of folding empty sequences
Operator Value when parameter pack is empty
* 1
+ int()
& -1
| int()
&& true
|| false
, void()
template < typename ... Empty >
void f( Empty ... e )
{// eは空のパラメーターパックとする

    auto x1 = ( e * ... ) ; // 1
    auto x2 = ( e + ... ) ; // int()
    auto x3 = ( e & ... ) ; // -1
    auto x4 = ( e | ... ) ; // int()
    auto x5 = ( e && ... ) ; // true
    auto x6 = ( e || ... ) ; // false
    auto x7 = ( e , ... ) ; // void()
}

これ以外のfold演算子で、空のパラメーターパックをfold式でパック展開しようとすると、ill-formedになる。

N4267: u8文字リテラル

charひとつで表現できるUTF-8文字リテラル。

char A = u8'A' ; // 0x41

主な使い方として、確実にASCII文字の数値をわかりやすいリテラルでソースコードに記述できる。

N4230: 名前空間のネスト

namespace A { namespace B { namespace C {
} } }

を、

namespace A::B::C {
}

のように書ける。

N4266: 名前空間と列挙子に属性

名前空間と列挙子に属性を指定することができる。C++14までは、文法上の問題で指定できなかった。

具体的には、[[deprecated]]を指定できるようになった。

namespace [[deprecated("Use new_lib")]] lib { }
namespace new_lib { }

enum struct E { value [[deprecated("Use VALUE.")]], VALUE } ;

ドワンゴ広告

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

今日は社内が盛り上がっていた。

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

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

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