C++17がISO/IEC 14882:2017として発行されました。
cpprefjpサイトでのC++17解説は、鋭意製作中です。
クラス内にstatic constexpr T
で宣言した定数を、std::vector::emplace_back()
関数とかに渡すと、リンクエラーになる場合があります。
ミニマムなコードとしては、以下のようになります:
struct X { static constexpr int x = 3; }; template <class T> void f(T&&) {} int main() { f(X::x); // リンクエラー : X::xの実体が見つからない }
クラスの静的定数は、宣言だけした場合にコピーはできますが、その変数のポインタや参照をとったりはできません。そのようなことをしたい場合は、どこかの.cpp/.ccといった拡張子のソースファイルで、変数を定義する必要があります。
struct X { static constexpr int x = 3; }; template <class T> void f(T&&) {} constexpr int X::x; // この翻訳単位にX::xの実体を置く int main() { f(X::x); // OK }
回避策として考えられるのは、以下のようなものです:
書籍『C++ Templates: The Complete Guide』の第2版が発売しました。
初版はC++03でしたが、今回の改訂でC++17対応しています。
この本は、『C++テンプレート完全ガイド』というタイトルで初版が邦訳されています。C++03のときに、この本にお世話になった人はすごく多かったと思います。新しくなってこの本が長く残ってくれるのは、うれしい限りですね。
Boost 1.65.0に重大なバグが何件かあったため、パッチバージョンアップしたBoost 1.65.1がリリースされました。1.65.0はスキップして1.65.1を使用してください。
1.65.1のリリースノートには、1.65.0の修正内容も含まれます。
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)がサポートされています。