Hatena::ブログ(Diary)

C++でゲームプログラミング

2011-12-14

[]template で T&&

rvalue reference については、こことか、こことか、ここら辺に詳しく書いてあります。


さて、rvalue reference ですが、簡単に説明すると次の様な挙動になります。


int n = 0;

int&& x1 = 0;
int&& x2 = n;   // error

これは関数で受け取る場合も同様で、


void
func(int&&){}

func(0);
func(n);    // error

このように lvalue で受け取る事は出来ません。

ただし、template 引数で受け取る場合はこれに限らず、


template<typename T>
void
T_func(T&&){}

T_func(0);
T_func(n);      // ok     T が int& となり && は無視される
T_func<int>(n); // error  int&& で受け取ろうとする

このように、lvalue でも受け取ることができます。

これは、T が T& になり、&& が無視されるからです。

(結果的に lvalue reference で受け取る)

これで T&& と書いておけば rvalue でも lvaleu でも問題なく受け取る事が出来ます。

ただし、明示的に型を指定する場合はその限りではないので注意して下さい。


[注意]

次のコードはエラーになります。


template<typename T>
struct holder{
	T value;
};

template<typename T>
holder<T>
make_holder(T&& t){
	return { t };
}

// error: conversion from 'holder<int&>' to non-scalar type 'holder<int>' requested
int n = 0;
holder<int> v = make_holder(n);

これは、T が T& になり、holder<T&> を返している為です。

これを解決するためには、std::remove_reference を使用します。


#include <type_traits>

template<typename T>
struct holder{
    T value;
};

template<typename T>
holder<typename std::remove_reference<T>::type>
make_holder(T&& t){
   return { std::forward<T>(t) };
}

int n = 0;
holder<int> v = make_holder(n); // ok

redboltzredboltz 2011/12/15 08:31 エントリの趣旨からはずれてしまうかもしれませんが、
holder<MovableType> v = make_holder(MovableType());
の場合にcopyせずmoveするために、
make_holder(T&& t){
return { std::forward<T>(t) };
}
とかすると、さらによい感じかと思ったり。

osyo-mangaosyo-manga 2011/12/15 08:52 おっと、確かにそうですね。
コメントありがとうございます!

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/osyo-manga/20111214/1323858919