SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

Visual C++ Compiler November 2013 CTP: "Torino"でできること

  • X ポスト
  • このエントリーをはてなブックマークに追加

rvalue reference v3

 右辺値参照(rvalue reference)の導入に伴い、コンストラクタとコピーの挙動が変わります。

list05
#include <iostream>
#include <type_traits>

using namespace std;

struct Noisy {
    Noisy() { cout << "ctor Noisy()\n"; }
   ~Noisy() { cout << "dtor ~Noisy()\n"; }
    Noisy(const Noisy&) { cout << "ctor Noisy(const Noisy&)\n"; }
    Noisy& operator=(const Noisy&) { cout << "copy Noisy(const Noisy&)\n"; return *this; }
    // -------- C++11 から、右辺値参照を引数とする コンストラクタ/コピーが追加された
    Noisy(Noisy&&) { cout << "ctor Noisy(Noisy&&)\n"; }
    Noisy& operator=(Noisy&&) { cout << "copy Noisy(Noisy&&)\n"; return *this; }
};

struct NoisyInt {
    Noisy noisy;
    int n = 123;
};

int main() {
    NoisyInt src;
    NoisyInt dst = move(src);
    dst = NoisyInt();
}

 コンストラクタ/コピーの挙動をモニタするNoisyをメンバに持つNoisyIntに対し、右辺値参照を引数とするコンストラクト/コピーを行っています。VC++12(現VS2013)では

list06
ctor Noisy()
ctor Noisy(const Noisy&)
ctor Noisy()
copy Noisy(const Noisy&)
dtor ~Noisy()
dtor ~Noisy()
dtor ~Noisy()

とプリントされるのに対し、Torinoでは

list07
ctor Noisy()
ctor Noisy(Noisy&&)
ctor Noisy()
copy Noisy(Noisy&&)
dtor ~Noisy()
dtor ~Noisy()
dtor ~Noisy()

となります。つまり、右辺値参照を引数としたコンストラクト/コピーが行われた際、内包するメンバそれぞれに対しても(正しく)右辺値参照コンストラクト/コピーが行われます。

reference qualifier

 右辺値/左辺値のどちらに対して適用されたかによって、メンバ関数を呼び分けられるようになります。メンバ関数宣言のおしりに&を付けると左辺値、&&を付けると右辺値です。

list08
#include <iostream>

using namespace std;

struct X {
    void f() &  { cout << "L-value\n"; }
    void f() && { cout << "R-value\n"; }
};

int main() {
    X x;
    x.f();   // L-value
    X().f(); // R-value
}

return type deduction

 C++11から、関数の戻り型を後置する書式が追加されました。

list09
// return type を後置する
auto plus(int x, int y) -> int {
  return x + y;
}

 関数テンプレートだと引数しだいで戻り型がころころ変わりうるため、decltypeが導入されています。

list10
template<typename T, typename U>
auto plus(const T& t, const U& u) -> decltype(t+u) { 
  return t + u;  
}
...
auto x = plus(10, 4); // int x = 14
auto y = plus(string("じゅう"), "よん"); // string y = "じゅうよん"

 Torinoに追加されたreturn type deductionは関数内のreturn 式;に基づいて戻り型を推論してくれるので、"-> 型"を省略できます。

list11
template<typename T, typename U>
auto plus(const T& t, const U& u) { // 戻り型を推論してくれる!
  return t + u;  
}
...
auto x = plus(10, 4); // int x = 14
auto y = plus(string("じゅう"), "よん"); // string y = "じゅうよん"

 ただし、これ"だけ"では期待する型を返してくれないことがあります。

list12
template<typename Container>
auto zeroth(Container& c) {
  return c[0]; 
}
...
std::vector<int> vi = { 10, 20, 30 };
++zeroth(vi); // 先頭要素をインクリメント...できない

 ダメなんですね、return型から推論される型はint&ではなく、intだと解釈されてしまうのです。

 この問題を解決すべく、decltype(auto)が用意されています。

list13
template<typename Container>
decltype(auto) zeroth(Container& c) {
  return c[0]; // Container::operator[]() の型を"そのまま"返す
}
...
std::vector<int> vi = { 10, 20, 30 };
++zeroth(vi); // 先頭要素をインクリメントする!

次のページ
generic lambda

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7598 2014/03/04 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング