江添亮の詳説C++17を読んで見る

https://ezoeryou.github.io/cpp17book/

気になる項目をピックアップ


変数テンプレート

変数テンプレートとは変数宣言をテンプレート宣言にできる機能

変数テンプレートの使い道は主に2つある。

  • 意味は同じだが型が違う定数
template < typename T >
constexpr T pi = static_cast<T>(3.1415926535) ;

template < >
Real pi<Real>("3.141592653589793238462643383279") ;

template < typename T >
T calc_area( T r )
{
    return r * r * pi<T> ;
  • traitsのラッパー
template < typename T >
constexpr bool is_pointer_v = std::is_pointer<T>::value ;
template < typename T, typename U >
constexpr bool is_same_v = std::is_same<T, U>::value ;

is_pointer_v<int> ;
is_same_v< int, int > ;

fold式

C++17にはfold式が入った。foldは元は数学の概念で畳み込みとも呼ばれている。

C++におけるfold式とはパラメーターパックの中身に二項演算子を適用するための式だ。

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

ネストされた名前空間定義

namespace A::B::C {
// ...
}

[[fallthrough]]属性

[[fallthrough]]属性はswitch文の中のcaseラベルを突き抜けるというヒントを出すのに使える。

case 1 :
    // 処理1
    [[fallthrough]]
case 2 :
    // 処理2
    break ;

[[nodiscard]]属性

[[nodiscard]]属性は関数の戻り値が無視されてほしくないときに使うことができる。[[nodiscard]]属性が付与された関数の戻り値を無視すると警告メッセージが表示される。

[[nodiscard]] int f()
{
    return 0 ;
}

[[maybe_unused]]属性

[[maybe_unused]]属性は名前やエンティティが意図的に使われないことを示すのに使える

演算子のオペランドの評価順序の固定

以下の式は、abの順番に評価されることが規格上保証される。@=@には文法上許される任意の演算子が入る(+=-=など)。

関数呼び出しの実引数のオペランドb1b2b3の評価順序は未規定のま

a.b
a->b
a->*b
a(b1,b2,b3)
b = a
b @= a
a[b]
a << b
a >> b

constexpr if文 : コンパイル時条件分岐

constexpr ifは、実はコンパイル時条件分岐ではない。テンプレートの実体化時に、選択されないブランチのテンプレートの実体化の抑制を行う機能

初期化文付き条件文

if ( auto ptr = std::make_unique<int>(42) ; ptr )
{
    // 処理
}

推定ガイド

クラステンプレートのコンストラクターからの実引数は便利だが、クラスのコンストラクターはクラステンプレートのテンプレートパラメーターに一致しない場合もある。そのような場合はそのままでは実引数推定ができない。このため、C++17には推定ガイドという機能が提供されている。

template < typename T >
class Container
{
    std::vector<T> c ;
public :
    // 初期化にイテレーターのペアを取る
    // IteratorはTではない
    // Tは推定できない
    template < typename Iterator >
    Container( Iterator first, Iterator last )
        : c( first, last )
    { }
} ;

template < typename Iterator >
Container( Iterator, Iterator )
-> Container< typename std::iterator_traits< Iterator >::value_type > ;

構造化束縛

    int a[] = { 1,2,3 } ;
    auto [b,c,d] = a ;

inline変数

inlineの現在の意味は誤解されている。

inline関数の意味は、「関数を強制的にインライン展開させるための機能」ではない

inlineキーワードにはインライン展開以外に、もう1つの意味がある。ODR(One Definition Rule、定義は1つの原則)の回避だ。

variant : 型安全なunion

variantは、型安全なunionとして使うことができる

std::monostatevariantの最初のテンプレート実引数として使うことでvariantをデフォルト構築可能にするための型

any : どんな型の値でも保持できるクラス

std::anyは、ほとんどどんな型の値でも保持できるクラス

optional : 値を保有しているか、していないクラス

ヘッダーファイル<optional>で定義されているoptional<T>は、T型の値を保有しているか、保有していないライブラリ

string_view : 文字列ラッパー

string_viewは、文字型(charwchar_tchar16_tchar32_t)の連続した配列で表現された文字列に対する共通の文字列ビューを提供する。文字列は所有しない。

並列アルゴリズム

並列アルゴリズムはC++17で追加された新しいライブラリだ。このライブラリは既存の<algorithm>に、並列実行版を追加する。

C++11では、スレッドと同期処理が追加され、複数の実行媒体が同時に実行されるという概念がC++標準規格に入った。

C++17では、既存のアルゴリズムに、並列実行版が追加された。

template <class InputIterator, class Predicate>
bool all_of(InputIterator first, InputIterator last, Predicate pred);
template <class ExecutionPolicy, class ForwardIterator, class Predicate>
bool all_of(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last,
            Predicate pred);

ハードウェア干渉サイズ(キャッシュライン)

VC++2019 では、std::hardware_destructive_interference_size が存在しないとエラーになった。(2019/7/16)

scoped_lock : 可変長引数lock_guard

    std::mutex a, b, c, d ;

    {
        // a,b,c,dをlockする
        std::scoped_lock l( a, b, c, d ) ;
        // a,b,c,dをunlockする
    }

ファイルシステム

ヘッダーファイル<filesystem>で定義されている標準ライブラリのファイルシステムは、ファイルやディレクトリーとその属性を扱うためのライブラリ

  • クラスpathでファイルパス文字列を扱う
  • 例外クラスfilesystem_errorとクラスerror_codeでエラー通知
  • クラスfile_statusでファイルの情報とパーミッションの取得、設定
  • クラスdirectory_entryでディレクトリーの情報の取得、設定
  • クラスdirectory_iteratorでディレクトリー構造をイテレーターとしてたどる
  • 多数のフリー関数でファイルとディレクトリーの操作