C++1z なんでも代入できるanyクラス

C++1zでは、コピー可能かムーブ可能であればどんな型でも代入できるanyクラスが入ります。C++には全ての型の継承元のobjectクラスというものはないので、その代わりにこのクラスを使えます。

このクラスのために、<any>ヘッダが新規追加されます。

#include <iostream>
#include <any>
#include <string>

int main()
{
  std::any a = 3; // int値を代入
  a = std::string("hello"); // stringオブジェクトを代入

  // 中身を取り出す
  // 取り出せなかったらstd::bad_any_cast例外
  try {
    std::string s = std::any_cast<std::string>(a);
    std::cout << s << std::endl;
  }
  catch (std::bad_any_cast& e) {
    std::cout << "bad_any_cast" << std::endl;
  }

  // 中身を取り出す
  // こちらは取り出せなかったらヌルポインタが返る
  if (std::string* s = std::any_cast<std::string>(&a)) {
    std::cout << *s << std::endl;
  }
  else {
    std::cout << "null" << std::endl;
  }
}

出力:

hello
hello

Boostと標準の差異

標準に採択されたanyは、Boostにあるanyとほぼ同じです。Boost 1.61.0時点のanyとの差異は、constexpr対応していることに加え、optionalvariantと共通の設計にするために、標準側に以下の機能があるくらいです:

この共通設計のために、Boostにある以下のメンバ関数はありません:

参照

お断り

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

C++1z shared_ptr::weak_type

C++1zから、shared_ptrの入れ子型としてweak_typeが追加されます。

これは、shared_ptr<T>に対するweak_ptr<T>型の別名です。

shared_ptrの要素型を取り出してweak_ptrのテンプレート引数を埋めることが冗長なコードになっていたための対処です。

shared_ptr<T> sptr = …;

// shared_ptrをweak_ptrに変換してラムダ式に渡す
auto f = [wptr = typename decltype(sptr)::weak_type(sptr)] {
  // この関数が呼ばれたときには、wptrが指す先のオブジェクトが死んでいる可能性がある
  if (wptr.lock()) {
    …
  }
}

参照

お断り

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

次回のBoost.勉強会は札幌です

Boost.勉強会 #20 東京に参加された皆さま、おつかれさまでした。発表資料はboostjpの以下のページにまとめてあります。

次回のBoost.勉強会は、札幌で行います。主催は@ignis_fatuusさんです。

明日はBoost.勉強会 東京です

明日はBoost.勉強会です。いつものように、IIJ様の会場をお借りして開催します。

私はBoost 1.61.0のアップデート内容と、C++1z (C++17になる予定のバージョン)の全容を解説します。

発表資料は、boostjpサイトの以下のページで公開する予定です。

C++1z not_fn

これまで、述語(predicate)を反転させるためには、std::not1()std::not2()という関数がありました。

これらの関数はそれぞれ1引数の述語関数オブジェクト、2引数の述語関数オブジェクトを対象としますが、C++11で導入された可変引数テンプレートがあれば、任意の引数を受け取る述語を扱えます。そのため、新たにstd::not_fn()という関数が定義されるようになります。

// <functional>
namespace std {
  template <class F>
  unspecified not_fn(F&& f);
}

この関数には、可変引数テンプレートの制限に引っかかることのない限り、任意の数の引数を受け取る述語関数オブジェクトを指定できます。

#include <cassert>
#include <functional>

int main()
{
    assert(std::not_fn([] { return true; })() == false);
    assert(std::not_fn([](int) { return true; })(1) == false);
    assert(std::not_fn([](int, int) { return true; })(1, 2) == false);
    assert(std::not_fn([](int, int, int) { return true; })(1, 2, 3) == false);
}

std::not()という関数名にしないのは、not予約語だからです。

std::not_fn()関数の追加にともない、以下の機能は非推奨となります:

  • std::not1()
  • std::not2()
  • std::unary_negate
  • std::binary_nagate
  • 標準関数オブジェクトのresult_typeargument_typefirst_argument_typesecond_argument_type

参照

お断り

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

C++1z basic_string::data()メンバ関数の非const版

basic_stringクラスが保持している動的文字配列の生ポインタを取得するdata()メンバ関数ですが、C++14まではconstメンバ関数のみ用意されていました。

C++1zでは、非const版のdata()メンバ関数が追加されます。これにより、char*を要求するインタフェースに対してstd::stringオブジェクトを使いやすくなります。

たとえば、なぜかchar*を要求するWindowsCreateProcess()関数のコマンドライン引数には、

BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // 実行可能モジュールの名前
  LPTSTR lpCommandLine,                      // コマンドラインの文字列 ←これ
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // セキュリティ記述子
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // セキュリティ記述子
  BOOL bInheritHandles,                      // ハンドルの継承オプション
  DWORD dwCreationFlags,                     // 作成のフラグ
  LPVOID lpEnvironment,                      // 新しい環境ブロック
  LPCTSTR lpCurrentDirectory,                // カレントディレクトリの名前
  LPSTARTUPINFO lpStartupInfo,               // スタートアップ情報
  LPPROCESS_INFORMATION lpProcessInformation // プロセス情報
);

C++1zでは以下のようにして引数を渡せます:

std::string applicationName;
std::string commandLineArgs;

// ...

if (CreateProcess(applicationName.data(), commandLineArgs.data(), /* etc. */)) {
  // etc.
}
else {
  // handle error
}

参照

お断り

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

C++1z emplace_frontとemplace_backで追加された要素を返す

シーケンスコンテナのemplace_front()メンバ関数emplace_back()メンバ関数は、C++14では戻り値型がvoidでしたが、C++1zでは追加された要素への参照が返るようになります。

これは、追加した要素をすぐ使いたい場合に、以下のような冗長なコードになっていた問題への対処です:

// case 1
my_container.emplace_back(…);
my_container.back().do_something(…);

// case 2
my_container.emplace_back(…);
do_something_else(my_container.back());

C++1zでは、このような状況で以下のように書けるようになります:

// case 1
my_container.emplace_back(…).do_something(…);

// case 2
do_something_else(my_container.emplace_back(…));

戻り値の型の変更は、ABIを破壊せず、パフォーマンスにも影響はありません。

変更対象は、シーケンスコンテナのemplace_front()emplace_back()、およびqueueクラスとstackクラスのemplace()メンバ関数になります。

push_front()push_back()は変更なしで、戻り値の型はこれまで通りvoidです。

参照

お断り

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

C++1z owner_lessで任意の要素型を持つshared_ptr同士を比較できるようにする

所有権ベースの小なり比較を行うstd::owner_less関数オブジェクトですが、そのクラステンプレートのパラメータによってスマートポインタの要素型を制約してしまうため、以下のような比較ができませんでした。

shared_ptr<int> sp1;
shared_ptr<void> sp2;
shared_ptr<long> sp3;
weak_ptr<int> wp1;

owner_less<shared_ptr<int>> cmp;
cmp(sp1, sp2); // コンパイルエラー
cmp(sp1, wp1);
cmp(sp1, sp3); // コンパイルエラー
cmp(wp1, sp1);
cmp(wp1, wp1); // コンパイルエラー

C++1zでは、std::owner_lessクラステンプレートにvoidの特殊化版が定義され、そのバージョンでは関数テンプレートの関数呼び出し演算子を持つようになります:

// デフォルトテンプレート引数がvoidになり、
template<class T = void> struct owner_less;

// voidに対する特殊化が追加
template<> struct owner_less<void> {
  template<class T, class U>
    bool operator()(shared_ptr<T> const&, shared_ptr<U> const&) const;
  template<class T, class U>
    bool operator()(shared_ptr<T> const&, weak_ptr<U> const&) const;
  template<class T, class U>
    bool operator()(weak_ptr<T> const&, shared_ptr<U> const&) const;
  template<class T, class U>
    bool operator()(weak_ptr<T> const&, weak_ptr<U> const&) const;

  typedef unspecified is_transparent;
};

これによって、異なる要素型を持つスマートポインタや、shared_ptr<void>のような特殊な要素型を持つスマートポインタとの比較ができるようになります。

参照

お断り

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

C++1z 時間の丸め演算

時間ユーティリティライブラリの<chrono>には、精度が下がる単位変換をする場合に使用するduration_cast()関数があります。

C++1zでは、このときの丸め演算をユーザーが選択するための機能が導入されます。

まず、整数を時間間隔の値型とするdurationのための、floor() (切り下げ)、ceil() (切り上げ)、round() (最近接偶数への丸め)。それと符号あり整数の時間間隔を持つdurationのためのabs() (絶対値)。

#include <iostream>
#include <chrono>

using namespace std::chrono;

int main()
{
    milliseconds ms(2500);
    seconds sec = round<seconds>(ms); // 500は精度落ちする

    std::cout << sec.count() << std::endl; // 2
}

それと、そのdurationを持つtime_pointのための、floor()ceil()round()が入ります。

Boost 1.61.0時点のBoost.Chronoライブラリには、durationに対するfloor()ceil()round()があります。

参照

お断り

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

C++1z hypot関数の3引数版

C++11で<cmath>に追加されたhypot()関数ですが、2引数(2次元)の演算のみが用意されていました。

C++1zでは、3引数版が追加されます。動機としては、科学計算や工学アプリケーションで3次元の演算をすることが多いためだそうです。

// <cmath>
namespace std {
  double hypot(double x, double y, double z);
  float hypot(float x, float y, float z);
  long double hypot(long double x, long double y, long double z);
}

この関数の効果:

{ \displaystyle
 \sqrt{x^{2} + y^{2} + z^{2}}
}

参照

お断り

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