2009-11-19 14 views
7

Qui ho funtore del tipo seguente:Come ridurre gli argomenti del modello?

template<class T, class Foo, T Foo::*p> 
struct X { 
    void operator()(Foo & f) { 
     (f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()` 
    } 

}; 

e il campione struct:

struct FF 
{ 
    int m; 
    int r; 
}; 

voglio usare il funtore X, ma io non voglio specificare esplicitamente argomento di template come segue :

void testforx() 
{ 
    std::vector<FF> cont(5); 
    std::for_each(cont.begin(), cont.end(), X<int, FF, &FF::r>()); // it work, but I don't want to write `int` and `FF` 
    std::for_each(cont.begin(), cont.end(), createx<&FF::r>());  // how I would like to use it, how to declare `createx` function? 
} 

Ecco quello che ho provato senza successo:

// that is what I tried, but it could not deduce T and Foo 
template<T Foo::*p, class T, class Foo> 
X<T, Foo, T Foo::*p> createx() 
{ 
    return X<T, Foo, p>(); 
} 

// this works, but requires to write T and Foo explicitly 
template<class T, class Foo, T Foo::*p> 
X<T, Foo, T Foo::*p> createx() 
{ 
    return X<T, Foo, p>(); 
} 
+0

Piccola correzione (il codice "corretto" non viene compilato): la dichiarazione del tipo restituito di 'createx' dovrebbe contenere' p' come terzo parametro del modello, non 'T Foo :: * p'. Non cambia il problema, comunque. –

risposta

8

io avrei Non conservare il puntatore membro come un argomento di un template:

template<class T, class Foo> 
struct X { 
    X(T Foo::*p): p(p) {} 
    void operator()(Foo & f) { 
     (f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()` 
    } 
private: 
    T Foo::*p; 
}; 

template <class T, class Foo> 
X<T, Foo> MakeX(T Foo::*p) 
{ 
    return p; 
} 

non credo sia possibile dedurre i tipi con il vostro approccio: non è possibile utilizzare un puntatore-a -Il membro è passato a una funzione in cui si verifica la detrazione del tipo.

Modifica: Ci possono essere soluzioni basate su macro, però.

Ad esempio, si può fare una classe per creare istanze X, in questo modo:

template <class T, class Foo> 
struct XMaker 
{ 
    template <T Foo::*p> 
    X<T, Foo, p> make() { return X<T, Foo, p>(); } 
}; 

Ora, è possibile creare un make ... funzione di dedurre T e Foo:

template <class T, class Foo> 
XMaker<T, Foo> make_x_maker(T Foo::*) 
{ 
    return XMaker<T, Foo>(); 
} 

che rende possibile scrivere una macro come:

#define CREATE_X(member) make_x_maker(member).make<member>() 

Uso:

std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r)); 
+0

È un codice di importanza temporale. Non voglio memorizzare 'p'. –

+2

La domanda era come scrivere 'createx'. Ho già una soluzione in fase di compilazione e voglio solo ridurre gli argomenti del template. –

+0

Ora questo è quasi di cui ho bisogno. Accetterei questa risposta ma non mi piacciono i macro. –

1

Non penso sia possibile ridurre il numero di argomenti del modello che si devono specificare se si desidera che un puntatore a funzione membro arbitrario sia un argomento modello.

Invece di funzione membro puntatori si potrebbe usare un parametro di tipo normale per un funtore che estrae un riferimento:

template<typename Func> 
class X 
{ 
public: 
    explicit X(Func f = Func()) : f(f) {} 

    template<class K> 
    void operator()(K & k) const { 
     f(k) = 12 * f(k); 
    } 
private: 
    Func f; 
}; 

Allora, avete ancora la possibilità di utilizzare uno speciale funtore che accede direttamente un certo membro (se si pensa che questo fornisce prestazioni migliori), o utilizzare un funcor accessor più generale che lo fa con un puntatore a funzione membro come membro.

+2

È consentito da Standard per avere un puntatore a funzione membro come argomento modello. –

+1

Sì, lo so. Il "Non credo sia possibile" si riferisce al titolo della domanda. Non ho detto che "i puntatori alle funzioni dei membri non sono consentiti come parametri del modello". Si prega di leggere le risposte con maggiore attenzione prima di downvotare. Cercherò di fare del mio meglio la prossima volta per scrivere risposte che non possono essere fraintese. Grazie. – sellibitze

+0

Questa risposta non ha nulla a che fare con la mia domanda. –

1

Avrei una domanda: hai davvero bisogno di specificare tutti quegli argomenti?

struct XR 
{ 
    template <class Foo> 
    void operator()(Foo& foo) const { foo.r = 12 * foo.r; } 
}; 

Questo funziona, non v'è alcuna necessità di un metodo più make funziona da solo:

void testforx() 
{ 
    std::vector<FF> cont(5); 
    std::for_each(cont.begin(), cont.end(), XR()); 
} 

preferisco non essere troppo generico quando creo modelli.

Se è necessario un operator() più complesso, è sempre possibile eseguire alcuni lavori pesanti all'interno.

Inoltre, è possibile considerare Boost.Bind se si desidera veramente estrarre le funzioni del puntatore e i riferimenti agli attributi.

EDIT:

Ho un'idea, che sarà un po 'diverso e non comporta alcun macro magia, e neppure nessuna magia metaprogrammazione.

Perché non utilizzare semplicemente un typedef e utilizzarlo?

Ok, potrebbe non essere automatizzato come si desidera ... ma è sufficiente digitare questo una volta, dopo tutto.

typedef X<int,FF,&FF::m> X_FF_m; // once 

std::for_each(cont.begin(), cont.end(), X_FF_m()); 

sembra meno di battitura di

std::for_each(cont.begin(), cont.end(), createX<&FF::m>()); 

ripetuto più e più volte.

Io uso a malapena modelli nudi nel mio codice, preferisco dattilografarli per migliorare la leggibilità.

+0

Non è un'opzione. 'struct XR' usa il membro' .r'. Se voglio usare il membro '.m' ho bisogno di definire una nuova' struct XM'? E che dire di un altro membro? –

+0

Una struttura per membro, niente di speciale, solo qualcosa che funziona ed è semplice. Ovviamente nel tuo esempio hai presentato una struttura con 2 attributi e penserei che si riduca abbastanza bene a 4 o 5 ... –

Problemi correlati