パスワードを忘れた? アカウント作成
100378 journal

eldeshの日記: 日本語はコンピュータサイエンス(?)に不向き! 6

日記 by eldesh
なんで(*)カインドと(Random)シードが両方とも「種」なのかと小一時間(ry
誰を問い詰めればいいんだろう?金田一先生?w

# 実際にはさほど困っているわけじゃないですが
99779 journal

eldeshの日記: 右辺値参照2/N(typo修正)

日記 by eldesh
右辺値参照続き.

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だった….

99478 journal

eldeshの日記: 右辺値参照1/N

日記 by eldesh
右辺値参照勉強中….

とりあえず分かったことを書いてみる.
(新しく分かったことだけ書くのでまとまってない.)

右辺値参照とは
  • せっかく作った一時変数を有効利用(エコ++)
  • 右|左辺値参照は値の性質ではなく,式の性質である.
  • 名前が付いてる式は左辺値参照である
  • 名前が付いてないなら右辺値参照である(ちょっと怪しいかも
  • 左辺値参照とオーバーロードできる
  • 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部終了.

99213 journal

eldeshの日記: vimへようこそ 2

日記 by eldesh
アキラさんがvimはじめたようなので,
現在の手元の環境を列挙してみる.
  • エディタ:Vim7(+ autocomplpop)
  • ファイラ:あふ(のキーバインドをいぢる)
  • ブラウザ:Firefox + vimperator
  • ウィンドウマネージャー:awesome(最近X自体触ってないけど)

これでかなりの作業がviライクなキーバインドで実現できますw
だれかVC++もそれっぽく動くようなプラグイン作ってくだしあ><;
他のviライクに操作できるソフト,(特に「あふ」に代わるファイラ)募集!

# slashdot日記が使いにくい….
# はてなerになろうかな…

97098 journal

eldeshの日記: 戻り値型型推論 2.0 3

日記 by eldesh
かなり前にSafiiさんに振られたネタだったけど,
明け方にふらふらしながら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を指定するのは,
インスタンス名(式)から推論するときに,まだ引数の解析が終わってないから(多分).

96093 journal

eldeshの日記: Wankuma勉強会に参加してきた

日記 by eldesh
Wankuma東京#33 に参加してきた.
Conceptでした.
auto(auto conceptの方)の意味が分かったので良し.
0xでautoの用途が増えすぎな気がする.
あとOracleの人お疲れ様です!(使うとこがシビアだと要求も厳しいですねw)

axiomは意味あるのか不明.使う人が,何を保証されてるのか (実行時にチェックされるのか,C++の上位言語が保証するのか,'なんとかして'コンパイラが保証するのか,exportみたいに無視される可能性があるのか) 分からないのは意味ないと思う.
書き手が保証している内容を記述するということにすれば,
コンパイラはハッピーだけど….


勉強会のあと別の飲み会へ
趣旨を忘れて明け方まで飲んでた(疲れた).いってらっしゃい(^^)/~~
95125 journal

eldeshの日記: a option型エミュレートしようとしたけど

日記 by eldesh
boost::optionalで十分だったよ…

template< typename T >
boost::optional<T> SOME( T const & e ){
    return optional<T>(e);
}
auto x = SOME(5);
(ry

もう他にやることが無かったw(更に少しも便利になってないorz)
NONEは作れないよなぁ…

次はコンパイルタイムoption型か?

91738 journal

eldeshの日記: 型計算で演算子オーバーロード(op[]編)

日記 by eldesh
書いてみた.
禁書目録インデックスを指定してリストから型を選択する.
やっぱりコンストラクタを呼び出すのが不格好だけど,
これはどうしようもなさげ.
型(の名前)にしか用がないのに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;
}

91238 journal

eldeshの日記: 型計算で演算子オーバーロード

日記 by 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+は逆にするべき?

typodupeerror

コンピュータは旧約聖書の神に似ている、規則は多く、慈悲は無い -- Joseph Campbell

読み込み中...