C++1z 戻り値を捨ててはならないことを指定する[[nodiscard]]属性

C++1zから、関数の戻り値をユーザーに無視しないでほしい場合に指定する[[nodiscard]]属性が導入されます。

この属性は、エラーが起きた状態でエラーを無視して正常として処理を続けないでほしいような状況で使用します。

struct error_info { … };

// 関数f()の戻り値は必ず使用すること
[[nodiscard]] error_info f();

int main()
{
    f(); // 戻り値を捨てている。(コンパイル時に警告が出力されることになるだろう)
}

エラー以外で使用する状況としては、以下のようなものが考えられます:

  • 自分自身を書き換えるのではなく、新しいオブジェクトを作って返すような関数
    • たとえば string replace(string origin, string old, string new); のような文字列の置換をする関数において、元となる文字列オブジェクトを書き換えるのではなく、置き換えた結果の新しい文字列を返すような場合。この場合、戻り値を使わないと単に無駄な処理になり、意図したコードではない可能性が高い
  • 戻り値を使って継続的な処理を行うような関数
    • futureを返す非同期処理の関数は、戻り値を無視すると即座にfutureのデストラクタが実行されて処理がブロッキングされるので、意図した処理ではない可能性が高い

この属性は、以下の要素に対して指定できます:

  • 関数宣言
  • クラスもしくは列挙型の宣言

[[nodiscard]]が指定された戻り値が使用されなかった場合、コンパイル時に警告が出力されることになるでしょう。

C++1z時点で、標準ライブラリに[[nodiscard]]が付く機能はとくにありません。

参照

お断り

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

Elixir/Phoenixでのchunked responseのサンプル

Elixir/Phoenixでのchunked responseのサンプルプロジェクトを作ってGitHubで公開しました。

HTTP 1.1のTransfer Encoding: chunkedです。サーバーからクライアントに、少しずつデータ分けて順次送っていくものです。

このサンプルプロジェクトでは、サーバーで実行したシェルスクリプトの標準出力をクライアントに順次送っています。

C++1z 使用しない可能性のある変数に対する警告を抑制するための[[maybe_unused]]属性

関数void f(int a) {}のパラメータaのように、実行時に使用しない可能性のある識別子は、コンパイル時に警告が出力されることがあります。

使用しないことが意図したものであることをコンパイラに伝えて警告を抑制するために、C++1zから[[maybe_unused]]属性が導入されます。

void f([[maybe_unused]] int a) {}

この属性は、以下の要素に対して指定できます:

  • クラスの宣言
  • 型の別名宣言
  • 変数の宣言
  • 非静的メンバ変数の宣言
  • 関数の宣言
  • 列挙型の宣言
  • 列挙子

この属性は、以下のような状況で有効活用できるでしょう:

  • シリアライズのバージョンパラメータ (アップデートでシリアライズ対象が増減しない限り、バージョンパラメータは使用しない)
  • assertマクロでのみ使用するパラメータ (リリースモードでのみ警告が出力されるのを抑制)

参照

お断り

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

C++1z フォールスルー時の警告を抑制する[[fallthrough]]属性

switch文で下のcaseに処理を流すことを「フォールスルー (fallthrough)」と言います。

#include <iostream>

int main()
{
    int n = 1;
    switch (n) {
        case 1:
            std::cout << "1" << std::endl;
            // break; を書かずに、処理を下に流す
        case 2:
            std::cout << "2" << std::endl;
            break;
    }
}
1
2

意図しないフォールスルーによってバグが発生することを防止するために、コンパイラがフォールスルーを検出して、コンパイル時に警告を出力する場合があります。

C++1zでは、意図したフォールスルーであることをコンパイラに伝え、警告を抑制するための[[fallthrough]]属性が導入されます。これは、フォールスルーしたい各caseの最後の式として記述します。一番下のcase/defaultには[[fallthrough]]属性は記述できません。

#include <iostream>

int main()
{
    int n = 1;
    switch (n) {
        case 1:
            std::cout << "1" << std::endl;
            [[fallthrough]]; // 意図したフォールスルーであることをコンパイラに伝える
                             // (警告が出力されない)
        case 2:
            std::cout << "2" << std::endl;
            break; // 一番下のcase/defaultに[[fallthrough]]を書くとコンパイルエラー
    }
}

参照

お断り

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

C++1z C標準ライブラリの参照をC11に更新

C++14段階では、C++標準ライブラリはC99のC標準ライブラリを参照していました。C++1zでは、C11標準ライブラリを参照するようになります。C11標準ライブラリのすべての機能に対応するわけではありません。

  • <stdatomic.h>, <stdnoreturn.h>, <threads.h>に対応するC++ヘッダは用意しない
  • <cfloat>に以下のマクロを追加
    • DBL_HAS_SUBNORM, FLT_HAS_SUBNORM, LDBL_HAS_SUBNORM : 非正規化数 (subnormal number)の有無を判定
    • DBL_DECIMAL_DIG, FLT_DECIMAL_DIG, LDBL_DECIMAL_DIG : 10進の桁数
    • DBL_TRUE_MIN, FLT_TRUE_MIN, LDBL_TRUE_MIN : 正の最小値
  • <cassert>には、C11で追加されたstatic_assertマクロを含めない
  • <cstdlib>aligned_alloc()関数を追加
  • <ctime>に、TIME_UTCマクロ, timespec構造体, timespec_get()関数を追加
  • <cstdio>vfscanf()関数を追加
  • <ccomplex>, <cstdalign>, <cstdbool>, <ctgmath>を非推奨化

参照

お断り

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

C++1z 非推奨だったiostreamのエイリアスを削除

標準入出力ライブラリで、C++98のころから非推奨だった型の別名と関数の別名が、C++1zで削除されます。

まず、std::ios_baseクラスの以下のメンバ型が削除されます:

namespace std {
    class ios_base {
    public:
        typedef T1 io_state;
        typedef T2 open_mode;
        typedef T3 seek_dir;
        typedef implementation-defined streamoff;
        typedef implementation-defined streampos;
    };
}
  • ios_base::io_stateの代わりにios_base::iostateを使用します。
  • ios_base::open_modeの代わりにios_base::openmodeを使用します。
  • ios_base::seek_dirの代わりにios_base::seekdirを使用します。
  • ios_base::streamoffの代わりに、char_traits<CharT>::off_typeもしくはbasic_ios<CharT>::off_typeを使用します。(<iosfwd>で定義されているstd::streamoffは残ります)
  • ios_base::streamposの代わりに、char_traits<CharT>::pos_typeもしくはbasic_ios<CharT>::pos_typeを使用します。(<iosfwd>で定義されているstd::streamposは残ります)

std::basic_streambufクラスの以下のメンバ関数が削除されます:

namespace std {
    template <class charT, class traits = char_traits<charT> >
    class basic_streambuf {
    public:
        void stossc();
    };
}

このメンバ関数は、同クラスのメンバ関数であるパラメータなしのsbumpc()を呼び出しているだけです。

ios_baseクラスの別名型が削除されることにともない、それらの型をパラメータにとる関数が削除されます。

namespace std {
    template <class charT, class traits>
    class basic_ios {
    public:
        void clear(io_state state);
        void setstate(io_state state);
        void exceptions(io_state);
    };

    template <class charT, class traits = char_traits<charT> >
    class basic_streambuf {
    public:
        pos_type pubseekoff(off_type off, ios_base::seek_dir way,
                ios_base::open_mode which = ios_base::in | ios_base::out);
        pos_type pubseekpos(pos_type sp,
                ios_base::open_mode which);
    };

    template <class charT, class traits = char_traits<charT> >
    class basic_filebuf : public basic_streambuf<charT,traits> {
    public:
        basic_filebuf<charT,traits>* open(const char* s, ios_base::open_mode mode);
    };

    template <class charT, class traits = char_traits<charT> >
    class basic_ifstream : public basic_istream<charT,traits> {
    public:
        void open(const char* s, ios_base::open_mode mode);
    };

    template <class charT, class traits = char_traits<charT> >
    class basic_ofstream : public basic_ostream<charT,traits> {
    public:
        void open(const char* s, ios_base::open_mode mode);
    };
}

参照

お断り

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

Boost 1.62.0がリリースされました

Boost 1.62.0がリリースされました。

リリースノートはいつものように、boostjpサイトで翻訳したものを公開しています。Flastさん、協力ありがとうございました。

新ライブラリ

今回の新ライブラリは、FiberとQVMの2つです。

Boost.Fiberは、ユーザースレッドのライブラリです。コルーチンをスレッドのインタフェースで使えるようにしたようなものです。軽量スレッドとして使えます。

Boost.QVMは、クォータニオン、ベクトル、行列のライブラリです。コンセプトベースで設計されているので、自分で作った型に対して、Boost.QVMのアルゴリズムを適用できます。

主要な更新

  • Boost.Containerに、C++1z関係の機能が入った。連想コンテナのsplice機能や、try_emplace()など
  • Boost.Coroutineライブラリが非推奨化した。Boost.Coroutine2への移行を推奨
  • Boost.Logに、プロセス間ロギングの機能が入った

今回はバグ修正が多く、目立った新機能はそれほどありません。

C++1z std + 数字の名前空間を予約

C++の今後のメジャーバージョンアップで標準ライブラリに大きな変更を加えるときのために、「std + 数字」の名前空間が予約されます。std2とかの名前空間を作りたいのだそうです。

参照

お断り

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

C++1z 並列アルゴリズムライブラリ

C++1zでは、並列アルゴリズムのライブラリが導入されることになりました。このライブラリは、<algorithm>, <numeric>, <memory>で定義されるアルゴリズムオーバーロードという形で提供されます。

using namespace std::execution; // 実行ポリシーの名前空間

std::vector<int> v = …

std::sort(v.begin(), v.end());      // これまで通りの順序実行
std::sort(seq, v.begin(), v.end()); // 明示的に順序実行を指定

std::sort(par, v.begin(), v.end());       // 並列実行を許可
std::sort(par_unseq, v.begin(), v.end()); // 並列and/orベクトル実行を許可

このライブラリの設計は、Thrustが元になっています。

実行ポリシー

並列アルゴリズムには、実行ポリシー (execution policy) を指定して使用します。実行ポリシーには、以下の種類があります:

実行ポリシー ポリシー値
順序実行
(これまで通りのシングルスレッド実行)
sequential_execution_policy seq
並列実行 parallel_policy par
並列実行および/もしくはベクトル実行 parallel_unsequenced_policy par_unseq

注意としては、実行ポリシーとして並列実行を指定した場合、規格上は「並列実行を許可する」というリクエストの意味になるということです。コンパイラやその他環境条件によっては、シングルスレッドで実行されるかもしれません。

実行ポリシーの定義は、新設される<execution>ヘッダで行われます。

実行ポリシーごとに型が付けられ、それらの型でオーバーロードができます。並列アルゴリズムの宣言としては、以下のようになります:

template <class ExecutionPolicy,
          class InputIterator, class Function>
void for_each(ExecutionPolicy&& exec,
              InputIterator first, InputIterator last,
              Function f);

並列アルゴリズムに対応するアルゴリズム

並列アルゴリズムは、<algorithm>, <numeric>, <memory>の全てが対象にはなりません。2016年9月段階では、以下のアルゴリズムが対象となります。

  • <algorithm>

    • adjacent_find
    • all_of
    • any_of
    • copy
    • copy_if
    • copy_n
    • count
    • count_if
    • equal
    • fill
    • fill_n
    • find
    • find_end
    • find_first_of
    • find_if
    • find_if_not
    • for_each
    • for_each_n (new)
    • generate
    • generate_n
    • includes
    • inplace_merge
    • is_heap
    • is_heap_until
    • is_partitioned
    • is_sorted
    • is_sorted_until
    • lexicographical_compare
    • max_element
    • merge
    • min_element
    • minmax_element
    • mismatch
    • move
    • none_of
    • nth_element
    • partial_sort
    • partial_sort_copy
    • partition
    • partition_copy
    • remove
    • remove_copy
    • remove_copy_if
    • remove_if
    • replace
    • replace_copy
    • replace_copy_if
    • replace_if
    • reverse
    • reverse_copy
    • rotate
    • rotate_copy
    • search
    • search_n
    • set_difference
    • set_intersection
    • set_symmetric_difference
    • set_union
    • sort
    • stable_partition
    • stable_sort
    • swap_ranges
    • transform
    • unique
    • unique_copy
  • <numeric>

    • adjacent_difference
    • exclusive_scan (new)
    • inclusive_scan (new)
    • inner_product
    • reduce (new)
    • transform_exclusive_scan (new)
    • transform_inclusive_scan (new)
    • transform_reduce (new)
  • <memory>

    • uninitialized_copy
    • uninitialized_copy_n
    • uninitialized_fill
    • uninitialized_fill_n

<numeric>については、並列アルゴリズムのほとんどが新たに作られることになります。

exclusive_scan()inclusive_scan()は、partial_sum()の亜種です。inclusive_scan()partial_sum()と同様に、先頭要素が出力に含まれます。exclusive_scan()の出力に先頭要素は含まれません。

reduce()accumulate()の亜種で、実行順序が非決定的になります。

transform_exclusive_scan()transform_inclusive_scan()は、1引数をとる変換関数で要素を変換した結果を、2引数をとる集計関数に渡します。transform + scanを同時に行います。transform_reduce()も同様に、transform + reduceを同時に行います。

参照

お断り

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

C++1z 初期化子リストからpairとtupleを構築しやすくするための改善

C++14では、以下のコードがコンパイルエラーになります。

std::tuple<int, int> pixel_coordinates() 
{
    return {10, -15};  // コンパイルエラー
}

struct NonCopyable { NonCopyable(int); NonCopyable(const NonCopyable&) = delete; };

std::pair<NonCopyable, double> pmd{42, 3.14};  // コンパイルエラー

C++1zではこれらが通るように、pairtupleのコンストラクタが、explicitと非explicitで適切にオーバーロードされるようになります。

explicitと非explicitでのオーバーロードにはSFINAEを使用しますが、規格書上のコンストラクタの定義にはenable_ifのような具体的な実装については出てこないため、EXPLICITと大文字で宣言が記述され、その定義の文章で「この場合はexplicit (、そうでなければ非explicit) となる」のような記述がされます。

例:

EXPLICIT constexpr pair(const T1& x, const T2& y);

注: …(略)… このコンストラクタは、is_convertible<const first_type&, first_type>::valuefalseもしくはis_convertible<const second_type&, second_type>::valuefalseである場合にのみexplicitとなる。

参照

お断り

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