eldeshさんのトモダチの日記、みんなの日記も見てね。 アナウンス:スラドとOSDNは受け入れ先を募集中です。
eldeshの日記: 日本語はコンピュータサイエンス(?)に不向き! 6
誰を問い詰めればいいんだろう?金田一先生?w
# 実際にはさほど困っているわけじゃないですが
eldeshの日記: 右辺値参照2/N(typo修正)
perfect fowarding
[左右]辺値参照とconstの有無でオーバーロードした関数に,
引数を転送するテンプレート関数を書きたいときに使用する転送テンプレート関数の書き方.
void hoge( string & );
void hoge( string const & );
void hoge( string && );
void hoge( string const && );
template< typename T >
void trans_hoge( T&& t ){
hoge(t);
}
string str("hoge"); // 左辺値
const string cstr("foo"); // constな左辺値
string bar(void){
return "bar";
}
string const bazz(void){
return "bazz";
}
trans_hoge(str); // hoge(string&)
trans_hoge(cstr); // hoge(string const&)
trans_hoge(bar()); // hoge(string&) !!
trans_hoge(bazz()); // hoge(string const&) !!
となって,左辺値参照Ver.が呼ばれてしまう.
なぜなら,hoge(t) tという名前が付いてるから(右辺値ではない)
これを回避するためには再度,名前を無くせば良い.
template< typename A >
struct Identity { // id a = a
typedef A type;
};
template< typename T >
T&& Forward( Identity<T>::type&& t ){ // reference collapsing 回避
return(t);
}
template< typename T >
void trans_hoge( T&& t ){
// 名前が無くなる
hoge(Forward<T>(t)); // 必ず<T>を明示
}
trans_hoge(bar()); // hoge(string&&) 計画通り!!
trans_hoge(bazz()); // hoge(string const&&) 計画通り!!
Identity::typeに無理やり&&を付与しているので,
reference collapsingが働かない.(なんで働かないのか厳密にはよく分からないorz)
ここで,通常の推論に任せると,trans_hogeの引数tの型はT&となるので,
Identity::type&&が参照の参照型となりコンパイルエラーとなってしまう.
これを回避するために,Forwardのパラメータ型は明示する必要がある.
Move semantics
右辺値参照の真髄(だと思う). 右辺値参照の参照先からリソースの所有権(つーかポインタ)を強奪する.
以下のような感じで使う.
class C {
public:
int *m_p;
C(int x) : x_(new int(x)) // a
{}
C( C& t ) : x_(new int(*t.m_p)) // b
{]
C( C&& t ) { // c
m_p = *t.m_p;
t.m_p = NULL;
}
};
class wrapperC {
C m_c;
public:
wrapperC(int x) : m_c(x){}
wrapperC( C&& c ) : m_c(Move(c)) {}
wrapperC( C& c ) : m_c(Move(c)) {}
wrapperC( wrapperC&& c ) : m_c(Move(c)) {}
};
C createC(int x){
C c(x);
return c;
}
wrapperC c0(5); // メソッドaが使われる
wrapperC c1(c0); // メソッドbが(ry
wrapperC c2( createC(6) ); // メソッドc(ry
wrapperC c2 = createC(7); // c(ry
03ではcreateC()でインスタンスが作られ,C(C&)でコピーされてから破棄されるが,
右辺値参照は,そこで破棄されるはずの一時変数に言及できるので,
ポインタ(メンバ)を横取りするだけでinstantiateが完了する.(代入も同じ)
さらにコンストラクタにMoveを書くだけで,
右辺値が来たときは勝手にMoveSemanticsが発動(?)し,
左辺値が来たときはコピーが動く!
とりあえずここまでで終了.(題名のNは2ということで)
だいたい理解したと思う.
まとめ:右辺値でおk
# 疲れた。
Mon Jul 6 14:29:58 2009 - wrapperCクラスのコンストラクタ名を修正.ひどいtypoだった….
eldeshの日記: 右辺値参照1/N
とりあえず分かったことを書いてみる.
(新しく分かったことだけ書くのでまとまってない.)
右辺値参照とは
- せっかく作った一時変数を有効利用(エコ++)
- 右|左辺値参照は値の性質ではなく,式の性質である.
- 名前が付いてる式は左辺値参照である
- 名前が付いてないなら右辺値参照である(ちょっと怪しいかも
- 左辺値参照とオーバーロードできる
- reference collapsionの振る舞いがややこしい(単なる主観)
とりあえず,(03でも使える)左辺値参照とオーバーロードして振り分けてみる.
void print(string const && str){
cout << "Rref:" << str << endl;
}
void print(string const & str){
cout << "Lref:" << str << endl;
}
string str("hoge"); // 左辺値
const string cstr("foo"); // constな左辺値
print(str); // Lref
print(cstr); // Lref
普通に受け取れる.
次は真打登場.
string bar(void){
return "bar";
}
string const bazz(void){
return "bazz";
}
print(bar()); // Rref
print(bazz()); // Rref
print()には,bar()とbazz()の返り値が入ってくるが,
処理系が作った一時変数(名無し)が入ってくるので,
右辺値参照として扱われる.
オーバーロードの規則
オーバーロードはまず,{左|右}で振り分けられてから, {const|か否か}で振り分けられる.
hoge( string const & str ){
cout << "const ref" << endl;
}
hoge( string && str ){
cout << "rvalue ref" << endl;
}
hoge(str); // const ref
hoge(cstr); // const ref
hoge(bar()); // rvalue ref
hoge(bazz()); // rvalue ref
reference collapsion
テンプレートパラメータの置き換えなどで,参照の参照(という型)が出来てしまった場合, ''&''を見なかったことにする規則. 左辺値参照(というか03)にもあるが最近知った.
template< typename T >
void print( T& t ){
}
string str("hoge");
string & p = str;
print<string&>(p); // valid
上の例では,printのパラメータ型がstring&なので, 単純に置き換えるとprintの引数型がT& &となってしまうが, reference collapsionが適用されるのでT& & -> T&として置き換えられる. 変換規則は以下.
ref_collapsing T | T& & = T&
| T&& & = T&
| T& && = T&
| T&& && = T&&
第1部終了.
eldeshの日記: vimへようこそ 2
現在の手元の環境を列挙してみる.
- エディタ:Vim7(+ autocomplpop)
- ファイラ:あふ(のキーバインドをいぢる)
- ブラウザ:Firefox + vimperator
- ウィンドウマネージャー:awesome(最近X自体触ってないけど)
これでかなりの作業がviライクなキーバインドで実現できますw
だれかVC++もそれっぽく動くようなプラグイン作ってくだしあ><;
他のviライクに操作できるソフト,(特に「あふ」に代わるファイラ)募集!
# slashdot日記が使いにくい….
# はてなerになろうかな…
eldeshの日記: 戻り値型型推論 2.0 3
明け方にふらふらしながらC++0xの話をしてたら, autoでの戻り値型型推論の理解(意味?)が怪しい事が判明したのでテスト.
decltypeは反則だよなーw(強力過ぎるという意味で)
#include <iostream>
#include <typeinfo>
using namespace std;
int I_D(double d){ return static_cast<int>(d); }
double I_D(int i){ return (i);
}
template< typename Arg >
auto wrapper( Arg arg ) -> decltype(I_D(arg))
{
cout << "type:" << typeid( decltype(I_D(arg)) ).name() << endl;
return I_D(arg);
}
int main(){
int x = wrapper(I_D(3.14));
double d = wrapper(I_D(4));
cout << x << ":" << d << endl;
return (0);
}
なんかしっくりきた感じ.
戻り値型の部分にautoを指定するのは,
インスタンス名(式)から推論するときに,まだ引数の解析が終わってないから(多分).
eldeshの日記: Wankuma勉強会に参加してきた
Conceptでした.
auto(auto conceptの方)の意味が分かったので良し.
0xでautoの用途が増えすぎな気がする.
あとOracleの人お疲れ様です!(使うとこがシビアだと要求も厳しいですねw)
axiomは意味あるのか不明.使う人が,何を保証されてるのか (実行時にチェックされるのか,C++の上位言語が保証するのか,'なんとかして'コンパイラが保証するのか,exportみたいに無視される可能性があるのか) 分からないのは意味ないと思う.
書き手が保証している内容を記述するということにすれば,
コンパイラはハッピーだけど….
勉強会のあと別の飲み会へ
趣旨を忘れて明け方まで飲んでた(疲れた).いってらっしゃい(^^)/~~
eldeshの日記: a option型エミュレートしようとしたけど
template< typename T >
boost::optional<T> SOME( T const & e ){
return optional<T>(e);
}
auto x = SOME(5);
(ry
もう他にやることが無かったw(更に少しも便利になってないorz)
NONEは作れないよなぁ…
次はコンパイルタイムoption型か?
eldeshの日記: 型計算で演算子オーバーロード(op[]編)
やっぱりコンストラクタを呼び出すのが不格好だけど,
これはどうしようもなさげ.
型(の名前)にしか用がないのにConstructable(かな?)を要求することがそもそもイヤだけどw
でもとりあえず満足 :)
ところで,戻り型にautoを指定した関数ってどういうシグネチャ持つんだ?
#include <string>
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <vector>
using namespace std;
template< int N >
struct Int {
enum { value = N };
};
template< int N, typename HD, typename ...TL >
struct at {
};
template< int N, typename HD, typename ...TL >
struct at<N,tuple<HD,TL...>> {
typedef typename at<N-1, tuple<TL...>>::type type;
};
template< typename HD, typename ...TL >
struct at<0,tuple<HD,TL...>> {
typedef HD type;
};
template< typename ...Seq >
struct TypeVector {
template< int N >
auto operator[]( Int<N> ) -> typename at<N,tuple<Seq...>>::type
{ }
};
int main(){
int v[] = { 1,2,3 };
at<3,tuple<int,string,double,vector<int>>>::type x(v,v+3);
cout << x[2] << endl; // 3
decltype(
TypeVector<int,string,double,vector<int>>()[ Int<1>() ]
) str("hogehoge");
cout << str << endl; // hogehoge
return 0;
}
eldeshの日記: 型計算で演算子オーバーロード
型の計算で演算子を使う雰囲気(?)なので下準備.
(インスタンスを足してるだけなので狡い気もするがw)
あとdecltypeはじめて使った.
例によってgcc4.4.0でコンパイル出来たけど, validなのかは全く自信ないのでご了承下さい><
using namespace std;
template< int N >
struct Int {
enum { value = N };
};
template< typename T, typename U >
struct Add {
typedef Int<T::value + U::value> type;
enum { value = T::value + U::value };
};
template< typename T, typename U >
typename Add<T,U>::type operator+( T const & t, U const & u ) { }
int main(){
int p;
string name;
name = typeid( decltype(
Int<1>() + Int<2>() + Int<3>() + Int<4>() + Int<5>()
) ).name();
cout << abi::__cxa_demangle(name.c_str(), 0, 0, &p) << endl;
return 0;
}
Addとop+は逆にするべき?