C++1z クラステンプレートのテンプレート引数推論

C++1zでは、クラステンプレートのテンプレート引数が推論されるようになります。

例として、冗長なコードになりがちなstd::lock_guardクラスを使用した以下のコードは、

std::mutex m1;
void f()
{
    std::lock_guard<std::mutex> lk(m);
}

C++1zでは以下のようにstd::lock_guardクラスのテンプレート引数を省略して書けるようになります:

std::mutex m;
void f()
{
    std::lock_guard lk(m);
}

この場合、mの型からstd::lock_guardクラスのテンプレート引数の型が推論されます。

C++1zでは、コンストラクタの引数からクラステンプレートのテンプレート引数が推論されます。std::lock_guardクラスの場合、先程のコンストラクタは以下のような宣言になっています:

template <class Mutex>
class lock_guard {
public:
    typedef Mutex mutex_type;
    explicit lock_guard(mutex_type& m);
};

このコンストラクタでは、その引数の型がそのままクラステンプレートのテンプレート引数になっているため、推論ができるようになっています。

ですが、変換コンストラクタのように、コンストラクタの引数から直接クラステンプレートのテンプレート引数を推論できない場合があります。イテレータ範囲を受け取るvectorのコンストラクタを考えます:

namespace std {
    // 簡略化したvectorとコンストラクタの宣言
    template <class T>
    class vector {
    public:
        template <class InputIter>
        vector(InputIter first, InputIter last);
    };
}

この場合は、引数の型InputIterからTを直接推論することはできません。このような場合には、ライブラリ側で推論の補助をする必要があります。推論補助は、クラステンプレートと同じスコープ (クラスの外)に、後置戻り値型 (trailing return type)と同じ構文で、コンストラクタに戻り値の型を明示します:

namespace std {
    template <class T>
    class vector {
    public:
        template <class InputIter>
        vector(InputIter first, InputIter last);
    };

    // 推論補助 (deduction-guide)
    template <class InputIter>
    vector(InputIter first, InputIter last)
        -> vector<typename iterator_traits<InputIter>::value_type>;
}

これでイテレータ範囲を受け取るvectorのコンストラクタでもクラステンプレートのテンプレート引数が推論できるようになり、以下のように書けるようになります:

std::list ls = {1, 2, 3};
std::vector v(ls.begin(), ls.end());

C++1z時点では、言語側の対応が入るのみで、標準ライブラリではクラステンプレートのテンプレート引数推論のための補助が入る予定はありません。

参照

お断り

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

編集履歴

  • 2016/10/25 12:47 : コメント欄でのk_satodaさんの指摘を受け、クラス内のコンストラクタに対して推論補助を記載していたところを、クラス外で推論補助するよう修正

C++1z 入れ子名前空間の定義

C++1zでは、ネストした(入れ子になった)名前空間の定義が簡潔に書ける構文が追加されます。

// C++14
namespace A { namespace B { namespace C {
}}}

// C++1z
namespace A::B::C {
}

入れ子名前空間の定義では、inlineや属性の指定はできません。

参照

お断り

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

C++1z 不明な属性を無視する

標準で定義される属性のほかに、実装定義の属性がありますが、その実装定義の属性を認識できない他の処理系では、その実装定義の属性は無視されることが規定されます。属性指定の文脈で#ifdefを書かなくてよくなります。

// GCC/Clangではgnu::deprecated属性が使用され、
// MSVC環境ではmaybe_raises_seh_exception (仮) が使用される
[[gnu::deprecated, msvc::maybe_raises_seh_exception]]
void f();

仕様としては、「認識できない属性トークンは、実装によって無視される」というものになります。実装ごとに適切な名前空間を用意することが推奨されるため、その処理系の名前空間内では、認識できない属性はコンパイルエラーか警告が出力されることになると考えられます。

参照

お断り

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

C++1z 属性の名前空間指定に繰り返しをなくす

標準外の属性は、名前空間内に定義されている場合があります (例として、GCCが定義している属性はgnu名前空間に属している)。属性指定の文脈でその名前空間を何度も書かなくてよいように、名前空間を省略するための機能がC++1zで入ります。

[[ using CC: opt(1), debug ]] void f() {}
  // [[CC::opt(1), CC::debug]] void f() {} と同じ意味

using指定できる名前空間は、ひとつだけのようです。

属性名前空間に対するusingの意味としては、「指定された属性がusingされた名前空間に属していればそれを使用する」というものになります。

参照

お断り

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

C++1z 名前空間と列挙子への属性付加を許可

C++1zでは、名前空間と列挙子の構文に、属性が付けられるようになります。標準の属性としては、[[maybe_unused]]属性が列挙子に付けられるようになります。

namespace 名前空間名 属性 {}
enum 列挙型 {
    列挙子 属性,
};

// [[maybe_unused]]属性の例
enum 列挙型 {
    列挙子 [[maybe_unused]],
};

参照

お断り

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

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の以下の階層の下に解説ページを用意する予定です。