C++1z 非推奨だったbool型に対するインクリメント演算子を削除

bool型に対してインクリメントすると固定でtrueになる仕様がありましたが、この仕様はC++98時点で非推奨になっていました。C++1zではこの機能が削除されます。

以下のようなコードは、C++1zではコンパイルが通らなくなりますので注意してください。

#include <cassert>

int main()
{
    bool b1 = false;
    bool b2 = true;

    // C++98から非推奨だがC++14まで合法、
    // C++1zではコンパイルエラー
    ++b1;
    b2++;

    assert(b1 == true);
    assert(b2 == true);
}

ちなみに、bool型に対するデクリメントは元々できません。

仕様としては、「算術型 (arithmetic type) に対してインクリメントできる」と書かれていたものが「(CV修飾された) bool型以外の算術型に対してインクリメントできる」に変わります。

参照

お断り

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

C++1z 非推奨だったregisterキーワードを削除

C++11から非推奨となっていたregisterキーワードが、C++1zで削除されます。

ただし、C++11のautoのように、registerキーワードを将来の標準でほかの用途に再利用することを考慮して、予約語としては残ります。

C++1zでは、register記憶クラス指定子を使用したプログラムは、コンパイルできなくなりますので注意してください。

参照

お断り

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

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