Boost 1.65.0がリリースされました。リリースノートの日本語訳は、いつものようにboostjpサイトで公開しています。
新ライブラリとして、PolyCollectionとStacktraceが追加されています。
Boost 1.65.0がリリースされました。リリースノートの日本語訳は、いつものようにboostjpサイトで公開しています。
新ライブラリとして、PolyCollectionとStacktraceが追加されています。
C++17で入る予定の、可変引数でミューテックスを受け取ってスコープを抜けたらロック解除するscoped_lock
クラスですが、C++17がDIS (Draft International Standard) の段階になり、仕様の手直しがもうほぼできない段階になってから、引数順の変更が行われました。
この変更は、ドラフト仕様 (Working Draft) としては、さらに次のバージョンのC++20に適用されました (Editor’s Reportを参照) 。しかし、libstdc++、libc++といった標準ライブラリの実装や、cppreferenceサイトなどでは、この変更がC++17に取り込まれたものとして扱っていました。
さらに、cppreferenceサイトでは、「この変更は、過去にリリースされたC++バージョンに遡って適用された」と書いてありました。そんなことが標準ドキュメントのどこに書いてあるのかわからず、また、過去のバージョンに遡って適用される変更がどれなのかわからないと、なにをC++17と言っていいのかわからなくなります。ですので、std-discussionメーリングリストで質問してみました。
この質問への返答を要約すると、以下のような扱いになっていました:
それと今回の場合、C++17はまだ策定が完了しておらず、その段階で標準ライブラリの全ての実装が、すでにこの変更に対応しています。ですので、今回の変更は少なくともC++17に含まれると考えられます。また、欠陥の修正は、どのバージョンの仕様書に適用されたかだけでなく、修正内容が報告された時期が重要で、実装にはすぐに適用されることがある、ということがわかりました。
とある事情から「インクルードするディレクトリが長いので何度も書きたくない」という状況になり、インクルードするディレクトリをマクロ定数に持って、インクルードするファイル名と連結してインクルードしたい、ということがありました。
そんなときの対応は、このようになりました:
// BOOST_PP_STRINGIZEと同等 // トークンを文字列化する #define PP_XSTR(M) #M #define PP_STR(x) PP_XSTR(x) // インクルードするディレクトリ。 // 最後が / になってはならない (トークンとして使えない文字、というエラーになる) #define MY_LIB_PATH aaa/bbb/ccc // aaa/bbb/ccc/ddd.hをインクルードする #include PP_STR(MY_LIB_PATH/ddd.h) int main() {}
https://wandbox.org/permlink/I6jGIJcqLE4RMHFE
最近cpprefjpに書いたものを列挙します。
assert
マクロがconstexpr関数内で使用できるようになったstd::next()
関数のイテレータ要件がForward IteratorからInput Iteratorに緩和されたstd::addressof()
がconst T&&
の引数を禁止にした。addressof<const T>(T())
のようにするとconst T&&
が指定できていたstd::addressof()
がconstexprに対応したstd::mutex
とかstd::recursive_mutex
のlock()
メンバ関数が、device_or_resource_busy
のエラーを起こらなくしたreserve()
メンバ関数が、C++14までn-1以上の予約していたが、C++17からn以上が予約されるようになったstd::shared_ptr<const void>
のようなテンプレート引数に対して間接参照演算子が適用できるようになったstd::get()
関数に、const T&&
版を追加。const付きで戻り値を返すと、その一時オブジェクトはconst T&&
になっていたためstd::atomic
クラスのテンプレート引数設定済みの別名として、atomic_uint8_t
のような固定幅整数型を追加std::atomic
クラスにvalue_type
とdifference_type
を追加。fetch
系の関数がT
ではなくdifference_type
を受け取るよう変更されたstd::numeric_limits::is_modulo
の符号あり整数型に対する仕様が変更された。これまでは符号あり整数型がオーバーフローしたときの未定義動作としての最小値に戻る挙動をtrue
として扱っていたのをやめた。規格上は符号あり整数型はfalse
で、処理系がオーバーフローしたときの動作をラップして最小値に戻る挙動として定義したときにtrue
となるようにしたstd::vector
とstd::deque
とstd::basic_string
のshrink_to_fit()
メンバ関数で、メモリを縮小して再割り当てが発生するときに、イテレータの無効化が起こることが明記された。明記されただけで、元々起こっていただろうstd::basic_string
のコンストラクタに、basic_string(const basic_string& str, size_type pos, const Allocator& a = Allocator());
のオーバーロードを追加標準ライブラリの仕様でnoexcept
が付いているものは、実装にもnoexcept
を付けることが求められます。
しかし、標準ライブラリの仕様でnoexcept
が付いていない場合、実装にnoexcept
を付けないことは求められません。
たとえば、libc++のstd::vector
クラスでは、以下のメンバ関数にnoexcept
が付いています。
// https://github.com/llvm-mirror/libcxx/blob/018a3d51a47f7275c59e802709104498b729522b/include/vector vector() noexcept(is_nothrow_default_constructible<allocator_type>::value); vector(vector&& x) noexcept(is_nothrow_move_constructible<allocator_type>::value); vector& operator=(vector&& x) noexcept( allocator_type::propagate_on_container_move_assignment::value || allocator_type::is_always_equal::value); void shrink_to_fit() noexcept; void swap(vector&) noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value || allocator_traits<allocator_type>::is_always_equal::value);
libstdc++のstd::vector
クラスでは、以下のメンバ関数にnoexcept
が付いています。
// https://github.com/gcc-mirror/gcc/blob/67886b40399e79bcc392a152e96d9116ba24e2ed/libstdc%2B%2B-v3/include/bits/stl_vector.h vector() noexcept(is_nothrow_default_constructible<_Alloc>::value); vector(vector&& __x) noexcept; vector(vector&& __rv, const allocator_type& __m) noexcept(_Alloc_traits::_S_always_equal()); vector& operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()); // swapで例外を投げそうなアロケータはコンパイルエラー void swap(vector& __x) _GLIBCXX_NOEXCEPT;
これにより、特定の標準ライブラリを使用する場合に、例外を投げない強い保証をするコードを書けることがあります (とくにデフォルトコンストラクタが有用)。また、仕様でnoexcept
が付いていない関数に対して、noexcept(式)
で例外を投げないかチェックすることにも意義があります。
Boost 1.64.0がリリースされました。リリースノートを日本語翻訳したものは、いつものようにboostjpサイトで公開しています。
今回はほとんどがバグ修正になっています。
Visual Studio 2017 (14.1)がサポートされています。
2017年中に改訂される予定のC++14の次のバージョン、仮称C++1zの更新内容をまとめました。正式名称はISO/IEC 14882:2017、通称C++17になる予定です。
C++17は、C++11ほど大きな変更はありませんが、重要な言語機能(構造化束縛とか)や、広く適用できるライブラリ機能が多く入っています。ライブラリは、ファイルシステムが入るのが大きいですね。ようやく標準ライブラリのみで、ファイルサイズを取得したり、ファイルのコピーや移動などを扱えるようになります。
策定体制として、Study Group (SG)と呼ばれる専門家グループがたくさん作られ、そこで同時並行に議論、策定が進められていた仕様のうち、固まったものがいくつかC++1zで導入されます。
それぞれの専門家グループで考えられた仕様はTechnical Specification (TS)という単位で個別に各国の承認をとっており、コンパイラでもstd::exprerimental
名前空間以下などで実験的に実装されていました。C++1zでは専門家グループで進められた仕様のうち、以下のものが入ります:
C++1zでは間に合わないですが、継続して議論が進められているTSもまだまだあり、このあと仕様が固まったものは、C++1zの次のバージョンC++2x (2020年、C++20予定) に入る予定です。そのなかには、コンセプト、モジュールシステム、トランザクショナルメモリ、並行コンテナ、コルーチン、ネットワークなどがあります。
TS以外の機能としても、多くの便利な機能が入ります。構造化束縛やif constexpr
文などは、とくに便利ですね。
言語機能の更新内容です。
T
に推論する[[maybe_unused]]
属性[[nodiscard]]
属性begin()
とend()
関数が、異なる型を返すことを許可[[fallthrough]]
属性if constexpr
文typename
キーワードの使用を許可auto
宣言[[fallthrough]]
属性[[maybe_unused]]
属性[[nodiscard]]
属性古くから非推奨だった機能が削除されます。非推奨になった機能は数バージョン先に削除される可能性がありますので、ご注意ください。
標準ライブラリの更新内容です。
optional
クラスvariant
クラスany
クラスswap
操作にnoexcept
を追加array
の変更操作にconstexpr
を追加emplace_front
とemplace_back
で追加された要素を返すmap
とunordered_map
に、挿入失敗時の動作を規定した新たなメンバ関数を追加basic_string
ライクな操作をするstring_view
basic_string::data()
メンバ関数の非const
版char_traits
のconstexpr
対応clamp()
関数not_fn
invoke()
関数reference_wrapper
がTriviallyCopyableであることを保証const
にするas_const()
関数shared_ptr
の配列対応shared_ptr::weak_type
shared_ptr::use_count()
の仕様を明確化し、unique()
を非推奨化shared_from_this
の指す先が書き換わらないことを規定unique_ptr
の型変換unique_ptr
のテンプレート代入演算子に、不足していたSFINAEルールを追加owner_less
で任意の要素型を持つshared_ptr
同士を比較できるようにするvoid_t
bool_constant
has_unique_object_representations
型特性古くから非推奨だった機能や、コンパイラの実装が不十分でユーザーにも使われてこなかった機能などが削除されます。非推奨になった機能は数バージョン先に削除される可能性がありますので、ご注意ください。
auto_ptr
, random_shuffle
, 古い<functional>
の機能を削除std::function
クラスのアロケータサポートを削除iostream
のエイリアスを削除これのほかにも、まとめていない細かい更新はたくさんあります。詳細な更新リストは、cpprefjp/siteリポジトリの以下のWikiページを参照してください。
この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。
using宣言 (using-declaration) には、2つの用途があります:
これらusing宣言に指定する識別子が、ひとつだけでなく、カンマ区切りで複数指定できるようになります。
C++11で可変引数テンプレートが導入されたことにより、派生クラスを定義する際に、基本クラスのリストを受け取ってまとめて多重継承できるようになりました。その際、using宣言の対象をひとつしか指定できなかったため、基本クラスと派生クラスでメンバ関数のオーバーロードをする場合、以下のように、再帰テンプレートによってusing宣言するという回避策をとる必要がありました:
#include <iostream> #include <iomanip> #include <utility> template <typename T, typename... Ts> struct Overloader : T, Overloader<Ts...> { using T::operator(); using Overloader<Ts...>::operator(); // 回避策:再帰でusing宣言 }; template <typename T> struct Overloader<T> : T { using T::operator(); }; template <typename... Ts> constexpr auto make_overloader(Ts&&... ts) { return Overloader<Ts...>{std::forward<Ts>(ts)...}; } int main() { auto o = make_overloader([] (auto a) {std::cout << a << std::endl;}, [] (float f) {std::cout << std::scientific << f << std::endl;}); o("hello"); o(1.2f); }
C++1zでusing宣言に複数の識別子を指定できるようになることで、これがより簡潔に書けるようになります。
#include <iostream> #include <iomanip> #include <utility> template <typename... Ts> struct Overloader : Ts... { using Ts::operator()...; // C++1z }; template <typename... Ts> constexpr auto make_overloader(Ts&&... ts) { return Overloader<Ts...>{std::forward<Ts>(ts)...}; } int main() { auto o = make_overloader([] (auto a) {std::cout << a << std::endl;}, [] (float f) {std::cout << std::scientific << f << std::endl;}); o("hello"); o(1.2f); }
using宣言のパック展開は、主な目的は先に示したメンバ関数のオーバーロードですが、副次的に、名前空間を省略するためのusing宣言も、カンマ区切りで複数指定できるようになります。
#include <iostream> int main() { using std::cout, std::endl; // C++1z // C++14まで // using std::cout; // using std::endl; cout << "hello" << endl; }
複数をカンマ区切りで指定できるだけなので、using std::cout, endl;
のように2つ目以降の指定で名前空間を省略するような書き方はできません。
この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。
std::shared_ptr
クラスのメンバ関数use_count()
とunique()
は参照カウンタがいくつあるか (リソースを共有しているユーザーが何人いるか) を返すもので、デバッグ目的にしか使用しません。また、複数スレッドから使用するには、仕様が不明確でした。
use_count()
は引き続きデバッグ目的の機能として残り、複数スレッドからのアクセスについて、仕様が明確化されます。現在の多くの実装が、同期しない読み込み (relaxed load) になっていたこともあり、use_count()
は仕様でも「同期しない」ことが明確化されます。そのため、複数スレッドからこのメンバ関数を使用する場合、戻り値で返される参照カウンタは「おおよその値」と見なし、ヒントとして扱うことになります。
unique()
メンバ関数の方は非推奨になります。この関数はuse_count() == 1
の結果のbool
値を返すものです。これが非推奨になるのは、use_count()
が複数スレッドからのアクセスに対して同期せず、「おおよその値」しか返さないことで、unique()
メンバ関数の戻り値の信頼性が高くないことが理由であると考えられます。
この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。
C++1zでは、unique_ptr<T[ ]>
と同様に、shared_ptr
もテンプレート引数をshared_ptr<T[ ]>
もしくはshared_ptr<T[N]>
のように指定することで、配列を扱えるようになります。
std::shared_ptr<double[1024]> p1 {new double[1024]}; std::shared_ptr<double[]> p2 {new double[n]}; // 添字アクセス double* p = p1[0];
shared_ptr<T[ ]>
はstd::vector<shared_ptr<T>>
と比べて、実装として参照カウンタがひとつで済みます。そのため、空間とパフォーマンスはshared_ptr<T[ ]>
の方が優れています。
この配列では、以下のような仕様の更新・追加があります:
element_type
を追加
T
を直接使用していたところを、配列も考慮した要素型element_type
を使用するように変更operator[ ]
を追加
std::reinterpret_pointer_cast()
関数を追加
shared_ptr<T[ ]> p;
をreinterpret_pointer_cast<U[ ]>(p)
でshared_ptr<U[ ]>
に変換する標準にshared_ptr
が入る以前、Boostにはshared_array
という配列を扱う専用のスマートポインタもありましたが、標準ではその設計は採用しませんでした。unique_ptr
を先に配列に対応したため、shared_ptr
はそちらに合わせて配列対応することになりました。
この配列対応は、Boostでは1.53.0から入っています。
make_shared()
の配列対応がN3939で提案されていますが、これはC++1zでは採用されていません。Boostでは1.56.0で対応しています。
shared_ptr
to Support Arraysshared_ptr
to Support Arrays, Revision 1shared_ptr
to Support Arrays, Revision 2shared_ptr
changes from Library Fundamentals to C++17shared_ptr
support for arraysこの記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。