Elixirでコンソールに出力する文字色を変更して戻す

# 緑(green) + 太字(bright)で"hello"を出力し、元の文字色に戻す(reset)
IO.puts IO.ANSI.format([IO.ANSI.bright <> IO.ANSI.green, "hello", IO.ANSI.reset])

# 元の文字色で"world"が出力される
IO.puts "world"

リリースマネージャのDistillerymix releaseしたあとにコンソールの文字色が戻らないバグがあって、調べて直してpull requestを送ったので、そのときに書いたミニマムコードです。

C++1z 全ての非型テンプレート引数の定数式評価を許可

C++1zでは、非型テンプレート引数(non-type template argument)で扱える型はとくに変わりませんが、渡せる値についての制限緩和が行われます。

今回緩和されるのは、ポインタの値です。C++14までは、以下のような制限がありました:

  • 静的記憶域を持つ完全オブジェクトへのポインタ値もしくは参照、もしくは
  • ヌルポインタ値に評価される定数式、
  • ヌルメンバポインタ値に評価される定数式であること

つまり、staticでないオブジェクトへのポインタは、ヌルポインタしか渡せなかったのです。

C++1zではこの制限が撤廃され、定数式で評価されるポインタならなんでも渡せるようになります。その許可される定数式での評価には、配列からポインタへの変換や、関数から関数ポインタへの変換、修飾の変換なども含まれます。

struct A {};

template <const A* p>
struct X {};

constexpr A a{};
constexpr A ar[3] = {};

constexpr const A* get_pointer() { return &a; }
constexpr const A* get_array_pointer() { return ar; }

int main()
{
    X<nullptr> {};             // OK : これまで許可されていた
    X<get_pointer()> {};       // OK : C++1z
    X<get_array_pointer()> {}; // OK : C++1z
}

参照

お断り

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

C++1z 非型テンプレートパラメータのauto宣言

C++14まで、以下のように書いていた「指定された型の定数を受け取る」意図の非型テンプレートパラメータ(non-type template parameter)ですが、

template <class T, T V>
struct X;

X<int, 3>;

C++1zではこの用途のためのシンタックスシュガー(糖衣構文、syntactic sugar)が導入されます。そのためには、テンプレートパラメータをautoにして値を受け取るようにします。

template <auto X>
struct A {};

A<3>;    // OK
A<true>; // OK
A<'a'>;  // OK
A<3.14>; // コンパイルエラー (浮動小数点数は渡せない)

テンプレートの中では、decltypeを使用すればXの型を取得できます。

このautoは、変数宣言のautoと同じくプレースホルダーという扱いになります。そのため、template <auto* P>template <auto& R>のような推論補助もできます。

#include <type_traits>

template <auto* X>
struct A {
    using type = decltype(X);
};

int main()
{
    constexpr int* p = nullptr;
    static_assert(std::is_same<A<p>::type, int*>{});
}

参照

お断り

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

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です。サーバーからクライアントに、少しずつデータ分けて順次送っていくものです。

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