2009-12-16 18 views
6

Si consideri il seguente codiceCome salvare il puntatore nel membro in fase di compilazione?

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 
}; 

Guardate, è possibile salvare qualsiasi parametro di modello se questo parametro è un TypeName o un valore intero. Il fatto è che il puntatore per il membro è un offset, vale a dire un numero intero. Ora voglio salvare qualsiasi puntatore a membro in fase di compilazione:

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)); 
} 

come salvare puntatore a membro a tempo di compilazione ? Io uso VS2008.

Nota. Il tempo di compilazione è fondamentale. Si prega di non scrivere la soluzione di run-time. Lo so.

+2

ha-ha, credo Moonshadow imparato qualcosa di nuovo oggi ... –

+0

@ Jon: infatti, appena scoperto chapeter 15.5: puntatori ai membri nel mio riferimento Stroustrup. * imbarazzato * – moonshadow

+0

avevo appena scritto una frase da esattamente quella sezione quando ho capito che avevi cancellato la tua risposta. Penso che il loro nome sia confuso però - non sono in realtà niente di simile ai puntatori. –

risposta

0

Perché utilizzare un modello?

#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; 
} 

Di seguito compila mp a questo su gcc-4.4.1 (non ho accesso al MSVC al momento):

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

è solo un offset al membro, che sembra un bel periodo di compilazione per me.

Con modello, è necessario specificare la definizione di fuori della classe:

#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)); 
} 

che compila a:

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 

Tuttavia questo tutti sa di libreria standard dispone di reimplementazione (vedi std::tr1::mem_fn).

+1

Semplicemente non capisci la mia domanda. –

+0

Quindi, per favore chiarisci la tua domanda, molte persone sembrano essere nella stessa barca. –

+0

Non essere offeso. Voglio salvare il puntatore al membro nella classe template come un tipo o un intero. Ho bisogno di * un puntatore ai tratti dei membri * come tratti del tipo. –

1

Non è possibile.

Tuttavia, è possibile utilizzare uno functionoid. Questo può essere una soluzione in fase di compilazione. E poiché il compilatore può incorporare elementi, è probabilmente anche più veloce di un puntatore a una funzione membro. Esempio:

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); 
} 

Non testato, ma si ottiene l'idea.

0

Non è possibile inizializzare un membro statico all'interno della definizione di una struttura. Deve essere dichiarato all'esterno in questo modo (che probabilmente non è quello che si intendeva con il modello, ma comunque):

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)); 
} 
+0

1) È una soluzione di run-time. 2) Questo metodo non utilizza i vantaggi dei modelli. Devo definire ogni volta un nuovo puntatore al membro per il caso di una nuova struttura e membri. –

+0

1) no, non lo è. 2) vero, ma quello era il progetto originale, ora scritto in un modo che il compilatore capisce. Non vedo alcun motivo per utilizzare un modello qui in primo luogo, basta renderlo una classe con un membro non statico e un costruttore di decodifica e il gioco è fatto. Molto più semplice ... – user231967

1

Sarebbe bello avere una spiegazione più elaborata del perché "la compilazione è importante" (aiuta a suggerire alternative). Ma per la mia idea tutto ciò che è ha bisogno di da fare in fase di compilazione con pointer-to-member, in realtà può fare do. La mia variante è il suggerimento di Thomas combinato con una certa filosofia di ordinamento C++. In primo luogo permette definire:

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

questo template struct può servire in modo efficace valore del tempo come di compilazione, e non hai bisogno di "valore statico = v;", si usa sia a compilazione o l'esecuzione.Considerare:

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

e

template <typename T> 
struct Bar; 

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

Foo e il bar sono funzionalmente equivalenti, ogni modello meta-kadabra che può essere fatto con Foo può essere fatto anche con Bar (basta passare val invece di n). Lo stesso Vay si può imballare puntatore al membro in val <>:

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

questi compilano i valori di tempo ora può essere memorizzati in liste di tipo (come boost :: :: MPL qualcosa), rispetto, trasformato, ecc, tutto compila il tempo. E quando si sarà finalmente voglia di usarli come puntatore a membro in fase di esecuzione, basta definire modello di una funzione:

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

e usarlo:

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

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

PS: ci sono alcuni costrutti maldestri su questa soluzione, ma è tutto per semplicità e spiegazione. Per esempio piuttosto brutto (a * estratto (A_i()).) Possono essere semplificate avvolgendolo in qualcosa di più puntatore-a-membro specifico:

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

dove mem_type è modello di classe che estrae tipo di membro di cui da M. Allora utilizzo potrebbe essere:

std::cout << mem_apply <a_i> (a); 
Problemi correlati