読者です 読者をやめる 読者になる 読者になる

C++1z has_unique_object_representations型特性

C++

少しまえから、オブジェクトからハッシュ値の計算を自動的に行いたい、という話がでていました。C++1z時点ではそのサポートは入りませんが、前準備として、自動的にハッシュ値を求められる型かを判別するためのhas_unique_object_representationsという型特性が入ります。

この型特性は、trivially copyableな型(memcpyできる型)やその配列に対して真を返します。

宣言

// <type_traits>
namespace std {
    template <class T>
    struct has_unique_object_representations : bool_constant<…> {};
}

2016年9月段階では、変数テンプレート版は予定されていません。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

ElixirでExcelデータを読み込むライブラリ

elixir

ElixirでExcelデータを読み込むライブラリはいくつかありますが、どれも自分の用途には微妙に適合しませんでした。インタフェースと戻り値のフォーマットはexcellentライブラリが好きだったのですが、Excel 2000のデータしか読み込めなかったので、xlsx_parserライブラリをラップしてexcellentライブラリライクに操作できるライブラリを書きました。

読み方は「エクセリオン」です。昔に同名のゲームがあったようですが、LとRが違います。s/excerion/excelion/ 。元ネタはゲームではなく小説の『黒の魔王』です。

xlsx_parserライブラリに、シート名のリストを取得する機能がなかったので、ライブラリの実装を調べてその機能を拡張しました。その機能はxlsx_parserライブラリにissueとして送ったらv0.0.8で取り込んでもらえました。

あとは、excellentライブラリと違う点として、読み込みを開始する行番号を指定できるようにしてあります。

ドキュメントはとりあえずソースコードに書いてありますが、余裕ができてきたらex_docで書きます。

C++1z 未初期化メモリのアルゴリズムと、デストラクタ呼び出しの関数

C++

C++標準ライブラリには、データ構造を実装する際に使用する未初期化メモリに対するアルゴリズム<memory>ヘッダで定義されています。

C++1zでは、厳しいパフォーマンス要求があるデータ構造を実装しやすくするためのアルゴリズムが、いくつか定義されます。これらは、std::vectorの内部実装や、EASTL、follyといったライブラリの実装で使われていたものです。

関数 説明
std::destroy_at()
std::destroy()
std::destroy_n()
指定された単一要素もしくは範囲の要素に対してデストラクタを呼び出す
(配置newした要素に対してよく使う)
std::uninitialized_move()
std::uninitialized_move_n()
未初期化メモリから要素をムーブ構築する
std::uninitialized_value_construct()
std::uninitialized_value_construct_n()
未初期化メモリから要素を値初期化で構築する
std::uninitialized_default_construct()
std::uninitialized_default_construct()
未初期化メモリから要素をデフォルト構築する

宣言

// <memory>
namespace std {
  template <class T>
  void destroy_at(T* location);

  template <class ExecutionPolicy, class ForwardIterator>
  void destroy(ExecutionPolicy&& exec, //see [algorithms.parallel.overloads]
               ForwardIterator first, ForwardIterator last);

  template <class ForwardIterator>
  void destroy(ForwardIterator first, ForwardIterator last);

  template <class ExecutionPolicy, class ForwardIterator, class Size>
  ForwardIterator destroy_n(ExecutionPolicy&& exec,//see [algorithms.parallel.overloads]
                            ForwardIterator first, Size n);

  template <class ForwardIterator, class Size>
  ForwardIterator destroy_n(ForwardIterator first, Size n);

  template <class ExecutionPolicy, class InputIterator, class ForwardIterator>
  ForwardIterator uninitialized_move(ExecutionPolicy&& exec,//see [algorithms.parallel.overloads]
                                     InputIterator first, InputIterator last, ForwardIterator result);

  template <class InputIterator, class ForwardIterator>
  ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result);

  template <class ExecutionPolicy, class InputIterator, class Size, class ForwardIterator>
  pair<InputIterator,ForwardIterator> uninitialized_move_n(ExecutionPolicy&& exec, //see [algorithms.parallel.overloads]
                                      InputIterator first, Size n, ForwardIterator result);

  template <class InputIterator, class Size, class ForwardIterator>
  pair<InputIterator,ForwardIterator> uninitialized_move_n(InputIterator first, Size n, ForwardIterator result);

  template <class ExecutionPolicy, class ForwardIterator>
  void uninitialized_value_construct(ExecutionPolicy&& exec, //see [algorithms.parallel.overloads]
                                     ForwardIterator first, ForwardIterator last);
  template <class ForwardIterator>
  void uninitialized_value_construct(ForwardIterator first, ForwardIterator last);

  template <class ExecutionPolicy, class ForwardIterator, class Size>
  ForwardIterator uninitialized_value_construct_n(ExecutionPolicy&& exec, //see [algorithms.parallel.overloads]
                                                  ForwardIterator first, Size n);

  template <class ForwardIterator, class Size>
  ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n);

  template <class ExecutionPolicy, class ForwardIterator>
  void uninitialized_default_construct(ExecutionPolicy&& exec, //see [algorithms.parallel.overloads]
                                       ForwardIterator first, ForwardIterator last);

  template <class ForwardIterator>
  void uninitialized_default_construct(ForwardIterator first, ForwardIterator last);

  template <class ExecutionPolicy, class ForwardIterator, class Size>
  ForwardIterator uninitialized_default_construct_n(ExecutionPolicy&& exec, //see [algorithms.parallel.overloads]
                                                   ForwardIterator first, Size n);

  template <class ForwardIterator, class Size>
  ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n);
}

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z unique_ptrのテンプレート代入演算子に、不足していたSFINAEルールを追加

C++

unique_ptrの以下の代入演算子に、オーバーロード解決に参加する条件が不足していました。

template <class U, class E>
unique_ptr& operator=(unique_ptr<U, E>&& u) noexcept;

C++14時点では、以下の2つの条件になっています。

  • unique_ptr<U, E>::pointerが、pointerに暗黙変換可能な型であること。
  • Uが配列型ではないこと。

C++1zでは、これに以下の条件が追加されます。

  • is_assignable_v<D&, E&&>trueであること

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z 乱数用語を変更

C++

C++11で導入された乱数ライブラリでは、乱数生成器のコンセプトに 「URNG (Uniform Random Number Generator, 一様乱数生成器)」という用語を使用していました。

しかし、一般的なURNGの用語とは異なり、C++の乱数生成器は一度の呼び出しで、(32ビットを超えるような) より多くのビットを単一の符号なし整数にパックして返すという動作が許可されています。URNGという用語を使用することは動作を誤解させることにつながりそう、と判断され、C++1zでは「URBG (Uniform Random Bit Generator)」という用語が代わりに使われるようになります。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z memory_order_consumeを一時的に非推奨化

C++

アトミック操作をする上で、処理の順序保証をする仕組みとしてメモリオーダーがあります。C++の標準ライブラリではメモリオーダーが何種類か提供されていますが、C++1zではmemory_order_consumeというメモリオーダーが一時的に非推奨になります。

memory_order_consumeは、データ依存性 (Data dependency) を調べて関連するデータの処理順序を保証するというものですが、ユーザーコミュニティから「その定義が現実に即していない」「acquire/releaseより弱いから使いにくい」といった意見が多く上がったため、よりよい定義に変更するまでの間、一時的にmemory_order_consumeが非推奨となります。

仕様上は「非推奨 (deprecated)」という扱いではなく、「仕様検討中」という注釈が付きます。

関連する機能として、std::kill_depency()関数や、[[carries_dependency]]属性があります。これらの機能もしばらく使わないことになるでしょう。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z std::functionクラスのアロケータサポートを削除

C++

C++11で導入されたstd::functionクラスには、アロケータを受け取るコンストラクタとassign()メンバ関数がありました。しかし、その仕様が不明確であったことから、正しい実装が行われてきませんでした。

  • GCCの標準ライブラリ実装であるlibstdc++では、アロケータを受け取るコンストラクタを提供していなかった
  • Clangの標準ライブラリ実装であるlibc++では、アロケータを受け取るコンストラクタはあったが、アロケータ引数は無視されていた
  • MSVCはアロケータを使用するが、代入の際にアロケータが伝搬されていなかった

そのため、これらの機能はC++1zで削除されます。

削除される機能

std::functionクラスの、アロケータを受け取るコンストラクタ、およびassign()メンバ関数

template<class A> function(allocator_arg_t, const A&) noexcept;
template<class A> function(allocator_arg_t, const A&, nullptr_t) noexcept;
template<class A> function(allocator_arg_t, const A&, const function&);
template<class A> function(allocator_arg_t, const A&, function&&);
template<class F, class A> function(allocator_arg_t, const A&, F);

template<class F, class A> void assign(F&&, const A&);

scoped allocatorから参照されるuses_allocatorの特殊化:

template<class R, class... ArgTypes, class Alloc>
struct uses_allocator<function<R(ArgTypes...)>, Alloc>
    : true_type { };

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z 古くなった機能を非推奨化

C++

C++1zから、標準ライブラリのいくつかの機能が非推奨となります。非推奨となった機能は将来のバージョンで削除される可能性がありますのでご注意ください。

std::iteratorクラス

自作イテレータを作るときに基本クラスとして使用するstd::iteratorクラスですが、これを使ってもイテレータを定義するのはあまり簡単になりませんでした。

このクラスを使用することによって問題がより複雑になってしまうケースもありましたので、非推奨となります。

Boost.Iteratorのようなイテレータを簡単に定義するための新たな仕組みは提供されませんので、標準ライブラリの範囲では、イテレータは最初から最後まで自分で定義することになります。

std::allocatorクラスのいくつかのメンバと、std::allocator<void>

C++11からアロケータの中間インタフェースとデフォルト実装を提供するstd::allocator_traitsクラスが導入されました。それにともない、std::allocatorの多くの機能はいらなくなりました。

そのため、std::allocatorクラスの以下のメンバは、非推奨となります:

また、rebind操作のために必要だったstd::allocator<void>も、std::allocator_traitsの機能でまかなえるようになったので、この特殊化も非推奨となります。

std::is_literal型特性

constexprで使用できる型が、C++のバージョンアップにつれて増えていっています。そのうち何でも(もしくはほとんどの型を)扱えるようにする予定のため、この型特性は非推奨となります。

この型特性がほんとうに必要にならなくなるくらいに何でもconstexprで扱えるようになったときに、この機能は削除されます。

temporary buffer関係

std::get_temporary_buffer()関数とstd::return_temporary_buffer()関数は、関数内での一時的なメモリ確保のために、最適化されたメモリ確保の仕組みを提供することを期待して定義されましたが、実際には誰も特別視せず、誰も使いませんでした。

将来的にスタックからメモリ確保をするdynarrayといった仕組みが検討されていますが、temporary buffer関係の現在のAPIは設計として例外安全性やRAIIといったものが考慮されていないため、dynarrayが入ったとしてもtemporary buffer APIの内部を改善することはできないと判断され、非推奨となります。

std::raw_storage_iteratorクラス

未初期化メモリを指すイテレータから、オブジェクトを構築していく出力イテレータstd::raw_storage_iteratorクラスですが、オブジェクトを構築していくのであれば、アロケータとの連携ができることが重要となります。

std::raw_storage_iteratorはそのような用途には適さないということで、非推奨となります。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z 隣接イテレータ

C++

C++1zから、イテレータの分類に「隣接イテレータ (contiguous iterator)」というものが追加されます。

ランダムアクセスイテレータだけではポインタ操作ができるかわからないので、メモリが隣接していることを表すイテレータの分類を追加することになりました。隣接イテレータは、ランダムアクセスイテレータの要件を含みます。

また、コンテナのiteratorおよびconst_iteratorが隣接イテレータであるコンテナは「隣接コンテナ (contiguous container)」と呼ばれます。

以下のコンテナは、隣接コンテナであることが規定されます:

C++1zの段階ではコンセプトだけを決めて、隣接イテレータや隣接コンテナを判定する仕組みは提供されません。

訳語の選択

  • 英語の似たような単語としてcontinuousとcontiguousがある。
  • continuousは「アメリカの州がつながっている」とか「ヨーローッパの国が地続きになっている」という用途に使われる。これが「連続」と訳されることが多い。
  • contiguousは、音楽アルバムでトラックごとのつながりのような文脈で使われる。これはadjacencyとの類義語。
  • メモリの文脈ではcontiguousが使われる。
  • 日本語のメモリの文脈でも「隣接」という言葉が使われているようなので、隣接を採用した。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。

C++1z 非推奨だったauto_ptr, random_shuffle, 古い<functional>の機能を削除

C++

C++1zでは、非推奨(deprecated)になっていた以下の機能が削除されます。既存のコードでこれらの関数を使用していた場合、コンパイルが通らなくなりますのでご注意ください。

古いスマートポインタ

  • std::auto_ptrクラス

C++11から非推奨。

代わりにstd::shared_ptrクラスやstd::unique_ptrクラスを使用してください。

古いバインダ

  • std::bind1st()関数
  • std::bind2nd()関数
  • std::binder1stクラス std::binder2ndクラス

C++11から非推奨。

代わりにstd::bind()関数もしくはラムダ式を使用してください。

関数ポインタから関数オブジェクトへの変換

  • std::ptr_fun()関数
  • std::pointer_to_unary_functionクラス std::pointer_to_binary_functionクラス

C++11から非推奨。

first_argument_typesecond_argument_typeといった型が必要なくなったため、これらの関数を使うことがなくなりました。

メンバ関数から関数オブジェクトへの変換

  • std::mem_fun()関数
  • std::mem_fun_ref()関数
  • std::mem_fun_tクラス
  • std::mem_fun1_tクラス
  • std::mem_fun_ref_tクラス
  • std::mem_fun1_ref_tクラス
  • std::const_mem_fun_tクラス
  • std::const_mem_fun1_tクラス
  • std::const_mem_fun_ref_tクラス
  • std::const_mem_fun1_ref_tクラス

C++11から非推奨。

代わりにstd::mem_fn()関数、std::bind()関数、ラムダ式といった機能を使用してください。

古いシャッフル関数

C++14から非推奨。

代わりにstd::shuffle()関数を使用してください。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。