読者です 読者をやめる 読者になる 読者になる

gl5_progのメモ

自分のためのメモとかまとめとか

C++で簡易タプルを実装してみる

http://ideone.com/FWKkVv

#include <stdio.h>

#define tempClassDef( num ) template<class T##num> struct tempClass##num       { T##num m##num; }; \
                            template<>             struct tempClass##num<void> {  }

tempClassDef( 0 );
tempClassDef( 1 );
tempClassDef( 2 );

template<class T0, class T1=void, class T2=void>
struct MyTupple : tempClass0<T0>, tempClass1<T1>, tempClass2<T2>
{
public:
};

class A
{
public:
    int m_Value;
    A() : m_Value(0) { printf( "A\n" ); }
    ~A(){ printf( "~A\n" ); }
};

class B
{
public:
    int m_Value;
    B() : m_Value(1) { printf( "B\n" ); }
    ~B(){ printf( "~B\n" ); }
};

class C
{
public:
    int m_Value;
    C() : m_Value(2) { printf( "C\n" ); }
    ~C(){ printf( "~C\n" ); }
};

int main( void )
{
    {
        printf( "sizeof( MyTupple<A,B,C> ) = %d\n", sizeof(MyTupple<A,B,C>) );
        MyTupple<A,B,C> myTupple;
        printf( "%d, %d, %d\n", myTupple.m0.m_Value, myTupple.m1.m_Value, myTupple.m2.m_Value );
    }
    {
        printf( "sizeof( MyTupple<C> ) = %d\n", sizeof(MyTupple<C>) );
        MyTupple<C> myTupple;
        printf( "%d\n", myTupple.m0.m_Value );
    }
    return 0;
}
sizeof( MyTupple<A,B,C> ) = 12
A
B
C
0, 1, 2
~C
~B
~A
sizeof( MyTupple<C> ) = 4
C
2
~C

タプルというかデータホルダーというか。

実装のポイント

  • 多重継承
  • 多重継承するには別の型でなければならない(そして別のメンバ変数名でないといけない)ので、そのような型を、対応するタプルの要素数分だけ作成しておく。(tempClassDef( 0 ); 〜 tempClassDef( 2 );)
  • テンプレート引数にデフォルト値(void)を与えることで、任意の要素数を実現
  • テンプレート引数がvoidの場合、テンプレートの特殊化で空structにすることで、「空の基底クラスの最適化*1」が働き、データサイズが無駄に大きくならない

多重継承ではなく、普通にメンバ変数として列挙するという方法もあるけど、それだとvoidの数だけ無駄にデータサイズが大きくなってしまう。

http://ideone.com/R9isTU

#include <stdio.h>

struct A   {};
struct AA  {};
struct AAA {};

// メンバ変数で複数の空structを持つ
struct MemVar
{
    A a;
    AA a1;
    AAA a2;
};

// 多重継承で複数の空structを持つ
struct MultiInherit : A, AA, AAA
{};

int main( void )
{
    printf( "sizeof( MemVar ) = %d\n", sizeof( MemVar ) );
    printf( "sizeof( MultiInherit ) = %d\n", sizeof( MultiInherit ) );
    return 0;
}
sizeof( MemVar ) = 3
sizeof( MultiInherit ) = 1

boostのタプルはどんな感じなのかな、とソースを見てみたけどちょっと意味不明だったのでそっと閉じました。