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

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