保存方法を指すポインタメンバをコンパイル時間がかかる?
-
19-09-2019 - |
質問
以下のコードを考えてみます:
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
};
見することができずテンプレートパラメータこのパラメータはtypenameまたは整数値です。ものであること ポイント会員 はオフセットする整数となります。今では、保存したい任意のポインタを会員にコンパイル時間:
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.
します。 コンパイル時には非常に重要です。ないでください書き実行時。知っています。
解決
なぜ用テンプレート?
#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;
}
以下の統 mp
これにgcc-4.4.1いないアクセス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
しかしこれ~だ標準ライブラリの特徴reimplementation参照 std::tr1::mem_fn
).
他のヒント
理由のより精巧な説明「コンパイル時間が重要である」持っていいだろう(代替案を示唆できます)。しかし、あなたはを私の概念のすべてがポインタ・ツー・メンバーとの時間をコンパイル実行する必要に、あなたが実際に<全角> のことができます。私の変種は、種のいくつかのC ++の哲学とブレンドトーマスの提案です。まず定義することができます:
template <typename T, T v>
struct val
{};
この構造体テンプレートは効果的のように、コンパイル時の値を提供することができます、そしてあなたは「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とバーが機能的に同等である、fooで行うことができるすべてのテンプレートメタkadabraもバーで行うことができる(ちょうどヴァルの代わりにNを通過します)。同じVAYあなたはヴァル<>にメンバーへのポインタをパックすることができます:
val <typeof (&My::a), &My::a>
これらは今(ブースト:: MPL ::何かのように)タイプリストに保存することができる時間値、比較、変換など、すべてが時間をコンパイルをコンパイルします。そして、あなたが最終的にただ一つの関数テンプレートを定義、ポインタ・ツー・メンバー実行時としてそれらを使用したいと思うでしょうときます:
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 ()));
P.Sは:このソリューションに関するいくつかの不器用な構築物はありますが、それはシンプルさと説明のためすべてです。むしろ醜い例えば(*エキス(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);
あなたがすることはできません。
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);
}
テストされていないが、あなたのアイデアを得る。
あなたは、構造体の定義の中の静的メンバを初期化することはできません。それは(とにかくあなたがテンプレートで意図したもので、おそらくされていないが、)このように外部に宣言する必要があります:
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));
}