本の虫

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

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

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

C++標準化委員会の文書: P0586R0-P0649R0

P0586R0: Safe integral comparisons

2つの整数型の値を安全に比較するためのライブラリの提案。

2つの異なる整数型の値を比較する時、符号が違ったり、一方がもう一方の表現できる範囲ではない場合、人間にとって不自然な結果になる。安全に比較するためには様々な符号や暗黙の型変換の考慮が必要だが、それを正しく書くのは面倒だ。なので標準ライブラリがほしい。

P0593R1: p0593r1: Implicit creation of objects for low-level object manipulation

以下の現行規格では未定義の挙動となるコードの挙動を規格で定義する提案。

struct X { int x ; } ;

int main()
{
    X * p = (X *) malloc( sizeof(X) ) ;

    p->x = 0 ; // 未定義の挙動

    free( p ) ;
}

このようなコードはC言語ではよく書かれるが、C++では未定義だ。構築されていないオブジェクトへのアクセスは未定義の挙動だ。このコードはオブジェクトを構築していない。したがって挙動は未定義だ。

しかし、現実を見ると、プログラマーはこのコードが動くことを期待しているし、現実のC++コンパイラーはこのコードの挙動について一致している。規格は現実を追認すべきだ。

すると、どのような型ならば制限を緩和するかということになるが、構築や破棄にあたってコードが実行されない型ならばよい。これには、スカラー型、配列型、トリビアルなコンストラクターとデストラクターを持つクラス型が当てはまる。

[PDF] P0609R1: Attributes for Structured Bindings

構造化束縛に属性を記述できる文法を追加する提案。

auto [a, b [[attribute]], c ] = e ;

[PDF] P0624R1: Default constructible stateless lambdas

stateless lambdaによって生成されるクロージャーオブジェクトをデフォルト構築可能にする提案。

auto f = (){} ;
decltype(f) g ; // OK
g() ; // OK

stateless lambdaならばクロージャーオブジェクトをデフォルト構築しても問題になることはない。クロージャーオブジェクトがデフォルト構築可能になることで、より汎用的に関数オブジェクトとして使いまわせる。

[PDF] P0631R1: Math Constants

数学定数を追加する提案。

ヘッダーファイルは既存のヘッダーファイルに追加するのであれば<cmath>か<numeric>、新しいヘッダーファイルにするのであれば<math_constants>が提案されている。

さて、数学定数はstd名前空間スコープの下に宣言されるわけだが、これは問題がある。というのも数学定数にはeといった小文字一文字の名前もあるので、以下のようなコードは壊れる。

using namespace std ;
int e ;

これは自業自得と言えば自業自得だが、とはいえ小文字一文字という名前はstd名前空間下であっても危険すぎる。

そのため、e_vのような形にするか、あるいはstd::math_constants下に置くという提案がされている。

提案では数学定数は変数テンプレートの形を取る。

template < typename T > inline constexpr T e ;

これにより任意の型に対応できる。

P0634R1: Down with typename!

依存名が型を意味するときにはtypenameを書かなければならないが、文脈上型しか書けない場所には書かなくてもすむようにする提案。

template < typename T >
auto f( T::type ) -> T::type
{
    using t = T::type ;
    new T::type ;
    static_cast<T::type *>(nullptr) ;
}

template < typename T >
struct A : T::type
{
    T::type t ;
} ;

現在の標準規格では以下のように書かなければならない。


template < typename T >
auto f( typename T::type ) -> typename T::type
{
    using t = typename T::type ;
    new typename T::type ;
    static_cast<typename T::type *>(nullptr) ;
}

template < typename T >
struct A : T::type
{
    typename T::type t ;
} ;

大変だ。

P0636R2: Changes between C++14 and C++17

C++14からC++17の間の変更点。

[PDF] P0642R1: Structural Support for C++ Concurrency

構造化プログラミングがループをパターン化して簡単に書けるようにしたように、並列処理をパターン化して簡単に書けるようにした並列処理に対する構造化サポートのためのライブラリの提案。

P0644R1: Forward without forward

forwardを書かずにforwardする提案。

Perfect Forwardingはだるい。例えば関数オブジェクトFuncに引数Argsを渡して戻り値を返す転送関数をPerfect Forwardingで書く場合

template < typename Func, typename ... Args >
decltype(auto) f( Func && func, Args && ... args )
{
    return std::forward<Func>(func)( std::forward<Args>(args)... ) ;
}

これをラムダ式で書く場合

auto f = []( auto && func, auto && ... args ) -> decltype(auto)
{
    return std::forward<decltype(func)>(func)( std::forward<decltype(args)>(args)... ) ;
}

とてもだるい。

そこで、この提案ではオーバーロード不可能な単項operator >>を追加することにより、適切なforwardingを行う昨日を提案する。

template < typename Func, typename ... Args >
decltype(auto) f( Func && func, Args && ... args )
{
    return (>>func)( >>args... ) ;
}

auto g = []( auto && func, auto && ... args ) -> decltype(auto)
{
    return (>>func)( >>args... ) ;
}

だいぶ楽になった。

[PDF] P0649R0: Other Product-Type algorithms

構造化束縛で分解できる型をproduct typeと呼び、その分解して得られる値を得るためのライブラリがP0327R2で提案されている。この提案は、product typeに対するtuple風アルゴリズムの提供だ。

たとえばfor_each

int main()
{
    std::tuple t(1, 3.14, "hello") ;

    std::product_type::for_each( [](auto x){ std::cout << x << '\n' ; }, t ) ;
}

構造化束縛できるあらゆるproduct typeに使えるfor_eachだ。他にも様々なアルゴリズムが提案されている。Boost.FusionやBoost.Hanaからアイディアを得ている。

ドワンゴ広告

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

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

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