C++1z 浮動小数点数の16進数リテラル

C++1zから、浮動小数点数リテラルを16進数で表記できるようになります。

たとえば、IEEE 754で定められている、単精度浮動小数点数の正の正規化数のうち最小の値である2-126は、10進数表現では1.17549e-38fですが、16進数で表記すれば0x1.0p-126fのように書きやすくなります。

#include <iostream>
#include <limits>

int main()
{
    std::cout << std::numeric_limits<float>::min() << std::endl; // ライブラリ機能で最小値を取得
    std::cout << 0x1.0p-126f << std::endl; // リテラルで最小値を直接表記する
    std::cout << std::hexfloat << 0x1.0p-126f << std::endl; // 16進数表記で出力
}

出力:

1.17549e-38
1.17549e-38
0x1p-126

標準ライブラリへの追従

C++11時点で、標準ライブラリでも浮動小数点数の16進数表現を扱ういくつかの機能がありました。

今回の機能追加は、ライブラリに言語機能が追従した形になります。

構文

浮動小数点数の16進数表現は、以下の構文になります:

  1. 頭に0xもしくは0Xを付ける (意味的な違いはない)
  2. 仮数
    1. 16進数の値
    2. 小数点 (仮数部の小数点数以下は省略可)
    3. 16進数の値
  3. 指数部
    1. p
    2. 符号 (+-か指定なし)
    3. 10進数の指数
  4. 浮動小数点数の型を決めるサフィックス

また、浮動小数点数の16進数リテラルもまた、ユーザー定義浮動小数点数リテラルの対象となります。

参照

お断り

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

C++1z インクルードするファイルが存在するかを確認する__has_include

C++1zから、インクルードするファイルが存在するかを確認するプリプロセッサ機能が追加されます。

__has_include式の引数として、ダブルクォーテーションで囲まれたインクルードファイル名、山カッコで囲まれたインクルードファイル名、もしくはプリプロセッサトークン名を指定することで、プリプロセス時にそのファイルが存在するかを#if#elifで確認できます。

// <optional>ヘッダが存在していたらインクルードする
#if __has_include(<optional>)
    #include <optional>
#endif
// "optional"ヘッダが存在していたらインクルードする
#if __has_include("optional")
    #include "optional"
#endif
#define OPTIONAL_HEADER <optional>

// <optional>ヘッダが存在していたらインクルードする
#if __has_include(OPTIONAL_HEADER)
    #include OPTIONAL_HEADER
#endif

参照

お断り

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

コンストラクタに用途別の名前を付ける

最近のC++標準ライブラリとBoostのちょっとした流行りな気がしますが、タグディスパッチのタグをユーザーに明示的に指定させることで、関数オーバーロードを容易にする方法がいくつかの場所でとられています。

たとえば、Boost.Containerのvectorには、以下のコンストラクタがあります。

// タグの定義
struct default_init_t {};
constexpr default_init_t default_init {};

// vectorのコンストラクタ
vector::vector(size_type, default_init_t);

// 3要素の配列を用意し、各要素の値を未初期化状態にする
vector<T> v(3, default_init);

この場合、単に3という1引数を渡すだけだと値初期化したリサイズ操作になりますが、default_initというタグを付けることによって「未初期化状態にする」というプログラマの意図を付加しています。

通常の関数だとこのような場合、別名の関数を用意して用途を分けますが、コンストラクタは名前がないのでこういったタグ付けが行われています。

C++標準ライブラリにもいくつかタグをユーザーが渡す場所があります。たとえば、ミューテックスを関数内でロック取得し、ロックを手放す操作を行うためのlock_guardクラスのコンストラクタがそうです。

mutex m;

void f()
{
    m.lock();

    // ロック取得済みのミューテックスを渡して、
    // スコープ終了時に自動的にロックを手放す
    lock_guard<mutex> lk(m, adopt_lock);
    // …共有リソースに対する操作...

} // ここでm.unlock()がlock_guardのデストラクタによって自動的に呼ばれる

このようなタグ付けは、コンストラクタオーバーロードに意味を持たせる目的に使えますので、便利に使っていい技法ではないかと思います。タグはおそらく、第1引数にするのがいいですね。意味を持たせてその用途の引数を渡す、という順番にすることでルールがわかりやすくなるので。

C++1z ラムダ式での*thisのコピーキャプチャ

ラムダ式のキャプチャリストにthisを指定した場合、そのラムダ式が所属するクラスのオブジェクトが参照キャプチャされます。

非同期処理や並列処理を記述するような状況で*thisが参照キャプチャされると、そのオブジェクトの寿命を管理するのが難しくなります。

C++1zではラムダ式のキャプチャリストに*thisを指定することで、*thisのオブジェクトがコピーキャプチャされるようになります。

std::vector<std::function<void()>> taskList;

struct X {
    void g();

    void f()
    {
        // *thisをコピーして、
        // コピーしたオブジェクトのメンバ関数g()を呼び出す関数をタスクリストに登録する
        taskList.push_back([*this] { g(); });
    }
};

=によるデフォルトコピーキャプチャ、および&によるデフォルト参照キャプチャは、どちらも従来通り*thisは参照キャプチャされます。*thisだけはコピーでキャプチャする新しいデフォルトキャプチャ記号も提案されましたが、採用はされていません。

[=, *this]のように、デフォルトコピーキャプチャと*thisによるコピーキャプチャは、同時に指定できます。

[this, *this]のように、*thisのキャプチャ方式を同時に複数指定することはできません。

参照

お断り

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

型のプレースホルダー

Boost.MPLのapplyメタ関数のように、プレースホルダーにしたテンプレート引数をあとで置き換える実装のサンプルです。

テンプレートテンプレートパラメータを使った部分特殊化で実装します。

#include <iostream>
#include <vector>
#include <list>

template <class T>
class my_vector {
    std::vector<T> data_;
public:
    void push_back(const T& x)
    { data_.push_back(x); }

    void print()
    {
        for (const T& x : data_) {
            std::cout << x << std::endl;
        }
    }
};

template <class T>
class my_list {
    std::list<T> data_;
public:
    void push_back(const T& x)
    { data_.push_back(x); }

    void print()
    {
        for (const T& x : data_) {
            std::cout << x << std::endl;
        }
    }
};

struct _ {};

template <class>
struct arg;

template <template <class> class T>
struct arg<T<_>> {
    template <class Arg>
    using apply = T<Arg>;
};

template <class Container>
class X {
    // 2. プレースホルダーになってるテンプレート引数をあとで置き換える
    typename arg<Container>::template apply<int> cont;
public:
    void push()
    { cont.push_back(3); }

    void print()
    { cont.print(); }
};

int main()
{
    X<my_vector<_>> x1; // 1. テンプレート引数をプレースホルダーにして
    x1.push();
    x1.print();

    X<my_list<_>> x2;
    x2.push();
    x2.print();
}

出力:

3
3

テンプレートテンプレートパラメータはテンプレート引数を埋めないと型になれないので扱いが難しいです。なので、テンプレートテンプレートパラメータを直接使うのではなく、プレースホルダーを使うか、Boost.Graphのadjacency_listのようにポリシー方式で渡すかにするのがよいです。

C++1z テンプレートテンプレートパラメータにtypenameキーワードの使用を許可

C++14まで、テンプレート関係で使用するキーワードとしてclasstypenameのどちらを使用するかをユーザーが選択できました。しかし、一部の状況ではどちらかしか使えません。

テンプレートテンプレートパラメータはC++14までclassキーワードしか使えませんでしたが、C++1zではtypenameも使用できるようになります。

#include <vector>
#include <list>

template <template <class...> typename Container>
class X {
    Container<int> cont;
};

int main()
{
    X<std::vector> x1;
    X<std::list> x2;
}

このコードでの、typename Containerの部分が、今回許可されるところです。

参照

お断り

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

C++1z static_assertのメッセージ省略を許可

C++11から導入されたコンパイル時アサートのstatic_assertですが、「式が真であると表明したいだけなのに、メッセージを指定しなければならないのがめんどくさい」という問題がありました。

この問題のために、ユーザーが以下のようにメッセージを省略するマクロをよく用意することになっていました。

// 指定した式を文字列化したものを、static_assertのメッセージとする
#define STATIC_ASSERT(EXPR) static_assert(EXPR, #EXPR)

C++1zからは、static_assertの第2引数であるメッセージが省略できるようになります。

constexpr int a = 1;
constexpr int b = 1;

static_assert(a == b);                      // 新機能。デフォルトのメッセージを使用する
static_assert(a == b, "a must equal to b"); // 従来のメッセージを明示的に渡す方法

メッセージを省略した場合、表明に失敗した際に出力されるメッセージの内容は未規定です。

参照

お断り

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

cpprefjp C++14の言語機能解説が完了しました

C++14 - cpprefjp C++日本語リファレンス

C++14の言語機能解説が一通りできました。C++11の方は残り11個なので、3月中くらいにできるかもしれません。

問題報告とpull requestは、cpprefjp/siteリポジトリまでお願いします。あとちょっと・・・。

広告の代わりに

cpprefjpサイトは現在、広告もなにも置いておらず、ビジネスモデルがない状態です。私個人宛てにはなりますが、応援してくださる方がいらっしゃいましたら、以下のAmazonウィッシュリストを見ていただければと思います。

Gitで、事前にUnicodeの結合を行う

WindowsMacリポジトリを共有していると、日本語ファイル名の問題が出てきます。「ボタン.png」のようなファイルがあった場合、Windowsファイルシステムでは「ボ」はひとつのコードポイントとして扱われますが、Macファイルシステムでは「ホ」と「゛」が分解されます。 これは、Unicodeの結合文字に対する正規化の扱いが、OSのファイルシステムごとに異なるということです。

これによって、Gitを使ってWindowsで「ボタン.png」をコミットし、Macでそのコミットを持ってくると、「ボタン.png」を削除して「ホ゛タン.png」を追加するような動作になるのです。

この問題を解決するために、Mac OSでのGit実装には、core.precomposeUnicodeという設定があります。configファイルで以下のようになっていた場合、

[core]
    …
    precomposeunicode = false

これをtrueに変更して保存します。

[core]
    …
    precomposeunicode = true

これで、Mac上でのGitリポジトリでは、事前にUnicodeの結合文字が結合され、Macファイルシステムで「ホ゛タン.png」が「ボタン.png」として見なされるようになります。

ドキュメントの翻訳

Git 2.7.1時点での、core.precomposeUnicodeの説明を翻訳して掲載しておきます。

このオプションは、GitのMac OS実装でのみ使用する。core.precomposeUnicode=trueとした場合、Mac OSでのファイル名のUnicode分解を元に戻す。これは、Mac OSLinuxWindows間でリポジトリを共有する際に役立つ。(Git for Windows 1.7.10以上が必要、もしくはGit under cygwin 1.7)。 これがfalseの場合、ファイル名はGitからは完全に透明に扱われ、古いGitとの後方互換性を持つ。

This option is only used by Mac OS implementation of Git. When core.precomposeUnicode=true, Git reverts the unicode decomposition of filenames done by Mac OS. This is useful when sharing a repository between Mac OS and Linux or Windows. (Git for Windows 1.7.10 or higher is needed, or Git under cygwin 1.7). When false, file names are handled fully transparent by Git, which is backward compatible with older versions of Git.

参照

cpprefjp - C++11で導入されたC99互換機能の解説を書きました

C99互換機能としてC++11に導入された機能の解説を、一通り書きました。

C++14の解説は残り3つ。C++11は残りいっぱいあります。