6

次のコードを検討してください

template<typename T, int N>
struct A {
  typedef T value_type; // OK. save T to value_type
  static const int size = N; // OK. save N to size
};

このパラメーターが型名または整数値である場合、任意のテンプレート パラメーターを保存できます。問題は、メンバーへのポインターがオフセット、つまり整数であることです。ここで、コンパイル時にメンバーへのポインターを保存します。

struct Foo {
   int m; 
   int r;
};

template<int Foo::*ptr_to_member>
struct B {
   // Next statement DOES NOT WORK!
   static int Foo::* const saved_ptr_to_member = ptr_to_member; 
};

// Example of using
int main() {
    typedef B<&Foo::m> Bm;
    typedef B<&Foo::r> Br;
    Foo foo;
    std::cout << (foo.*(Bm::saved_ptr_to_member));
}

コンパイル時にメンバーへのポインターを保存する方法は? 私はVS2008を使用しています。

ノート。コンパイル時間は重要です。ランタイム ソリューションを記述しないでください。私はそれを知っている。

4

4 に答える 4

4

「コンパイル時が重要である」理由をより詳細に説明しておくと便利です(代替案の提案に役立ちます)。しかし、私の考えでは、メンバーへのポインターを使用してコンパイル時に実行する必要があるすべてのことを、実際に実行できます。私の変種は、ある種のC++哲学とブレンドされたThomasの提案です。最初に定義しましょう:

template <typename T, T v>
struct val
{};

この構造体テンプレートは、コンパイル時の値として効果的に機能します。コンパイル時または実行時に使用するために、「static value=v;」は必要ありません。検討:

template <int n>
struct Foo
{
  //something dependent on n
};

template <typename T>
struct Bar;

template <int n>
struct Bar <val <int, n> >
{
  //something dependent of n
};

FooとBarは機能的に同等であり、Fooで実行できるすべてのテンプレートメタカダブラはBarでも実行できます(nの代わりにvalを渡すだけです)。メンバーへのポインタをval<>にパックできるのと同じ方法です。

val <typeof (&My::a), &My::a>

これらのコンパイル時の値は、すべてのコンパイル時のタイプリスト(boost :: mpl :: somethingなど)に格納したり、比較したり、変換したりできるようになりました。そして、最終的に実行時にメンバーへのポインターとしてそれらを使用したい場合は、1つの関数テンプレートを定義するだけです。

template <typename T, T value>
T
extract (val <T, value>)
{
   return value;
}

そしてそれを使用します:

typedef val <typeof (A::i), A::i> a_i;

A a;
std::cout << (a .* extract (a_i ()));

PS:このソリューションには不器用な構成がいくつかありますが、それはすべて単純化と説明のためです。たとえば、かなり醜い(。*抽出(a_i()))は、メンバー固有のポインタにラップすることで簡略化できます。

template <typename M, typename C>
typename mem_type <M>::value &
mem_apply (C &c)
{
   M m;
   return c .* extract (m);
}

ここで、mem_typeは、Mによって参照されるメンバーのタイプを抽出するクラステンプレートです。その場合、使用法は次のようになります。

std::cout << mem_apply <a_i> (a);
于 2011-03-12T09:36:56.570 に答える
1

テンプレートを使用する理由

#include <cstdio>

struct Foo {
    int a;
    int b;
} foo = {2, 3};

int const (Foo::*mp) = &Foo::b;

int
main() {
    printf("%d\n", foo.*mp);
    return 0;
}

以下は、gcc-4.4.1 でこれにコンパイルmpされます (現時点では MSVC にアクセスできません)。

.globl mp
        .align 4
        .type   mp, @object
        .size   mp, 4
mp:
        .long   4

それはメンバーへの単なるオフセットであり、私にはかなりコンパイル時に見えます。

テンプレートを使用すると、クラスの外側で定義を指定する必要があります。

#include <cstdio>

struct Foo {
   int m;
   int r;
} foo = {2, 3};

template<int Foo::*Mem>
struct B {
   static int Foo::* const mp;
};

template<int Foo::*Mem>
int Foo::* const B<Mem>::mp = Mem;

int main() {
    typedef B<&Foo::m> Bm;
    typedef B<&Foo::r> Br;
    printf("%d, %d\n", foo.*(Bm::mp), foo.*(Br::mp));
}

コンパイルすると次のようになります。

g++ -O2 -S -o- b.cc | c++filt

...

        .weak   B<&(Foo::r)>::mp
        .section        .rodata._ZN1BIXadL_ZN3Foo1rEEEE2mpE,"aG",@progbits,B<&(Foo::r)>::mp,comdat
        .align 4
        .type   B<&(Foo::r)>::mp, @object
        .size   B<&(Foo::r)>::mp, 4
B<&(Foo::r)>::mp:
        .long   4
        .weak   B<&(Foo::m)>::mp
        .section        .rodata._ZN1BIXadL_ZN3Foo1mEEEE2mpE,"aG",@progbits,B<&(Foo::m)>::mp,comdat
        .align 4
        .type   B<&(Foo::m)>::mp, @object
        .size   B<&(Foo::m)>::mp, 4
B<&(Foo::m)>::mp:
        .zero   4

ただし、これはすべて標準ライブラリ機能の再実装の一部です (「参考文献」を参照std::tr1::mem_fn)。

于 2009-12-16T10:57:39.610 に答える
1

できません。

ただし、代わりに関数型を使用できます。これ、コンパイル時の解決策になる可能性があります。また、コンパイラはインライン化できるため、メンバー関数へのポインターよりも高速になる可能性があります。例:

struct Foo {
   int m; 
   int r;
};

struct FooM {
   static int call(Foo const &foo) const { return foo.m; }
}

struct FooR {
   static int call(Foo const &foo) const { return foo.r; }
}

template<typename FooFun>
struct B {
   typedef FooFun foo_fun;
   int call_foo_fun(Foo const &foo) { return foo_fun::call(foo); }
};

// Example of using
int main() {
    typedef B<FooM> Bm;
    typedef B<FooR> Br;
    Foo foo;
    std::cout << Bm.call_foo_fun(foo);
}

テストされていませんが、アイデアはわかります。

于 2009-12-16T09:57:59.650 に答える
0

構造体の定義内で静的メンバーを初期化することはできません。このように外部で宣言する必要があります (これはおそらくテンプレートで意図したものではありませんが、とにかく):

struct Foo {
   int m; 
   int r;
};

template<int Foo::*ptr_to_member>
struct B {
   static int Foo::* const saved_ptr_to_member; 
};

int Foo::* const B<&Foo::m>::saved_ptr_to_member = &Foo::m; 
int Foo::* const B<&Foo::r>::saved_ptr_to_member = &Foo::r; 

// Example of using
int main() {
    typedef B<&Foo::m> Bm;
    typedef B<&Foo::r> Br;
    Foo foo;
    std::cout << (foo.*(Bm::saved_ptr_to_member));
}
于 2009-12-16T10:35:45.987 に答える