2009-08-30 11 views

risposta

11

Questo compila, utilizzando l'estensione __typeof__ GCC. Sembra che GCC's valarray utilizzi modelli di espressioni per ritardare il calcolo del seno. Ma questo renderà il tipo di ritorno del modello sin non esattamente valarray<T>, ma piuttosto un tipo strano e complesso.

#include <valarray> 

template<typename T> struct id { typedef T type; }; 
int main() { 
    using std::valarray; 
    using std::sin; 

    id<__typeof__(sin(valarray<double>()))>::type (*fp)(const valarray<double> &) = sin; 
} 

Edit: citazione di serie Sede di AProgrammer del motivo per cui GCC è bene farlo.

Edit: standard compliant soluzione

Facendo questo senza __typeof__ in modo conforme rigorosamente standard è un po 'complicato. Dovrai ottenere il tipo di reso sin. È possibile utilizzare l'operatore condizionale per questo, come Eric Niebler has shown. Funziona con la funzione sin non effettivamente chiamata, ma solo con la verifica del tipo.Cercando di convertire l'altro ramo (quello che in realtà è valutata) dell'operatore condizionale per lo stesso tipo, possiamo generare un parametro fittizio solo essere in grado di dedurre la tipologia del puntatore funzione:

#include <valarray> 

using std::valarray; 

template<typename T> struct id { 
    typedef T type; 
}; 

struct ded_ty { 
    template<typename T> 
    operator id<T>() { return id<T>(); } 
}; 

template<typename E, typename T> 
id<T(*)(valarray<E> const&)> genFTy(T t) { 
    return id<T(*)(valarray<E> const&)>(); 
} 

template<typename T> 
void work(T fp, id<T>) { 
    // T is the function pointer type, fp points 
    // to the math function. 
} 

int main() { 
    work(std::sin, 1 ? ded_ty() : genFTy<double>(std::sin(valarray<double>()))); 
} 

Se si desidera ottenere l'indirizzo subito, è possibile scrivere work in modo che restituisca nuovamente fp.

template<typename T> 
T addy(T fp, id<T>) { return fp; } 

Ora, si può finalmente scrivere una macro per incapsulare l'inganno operatore condizionale, e usarlo quando si vuole ottenere l'indirizzo di tale funzione matematica.

#define DEDUCE(FN,Y) (1 ? ded_ty() : genFTy<Y>(FN(std::valarray<Y>()))) 

per ottenere l'indirizzo e passare a qualche funzione generica, le seguenti opere poi

std::transform(v1.begin(), v1.end(), v1.begin(), 
    addy(std::sin, DEDUCE(std::sin, double))); 
std::transform(v2.begin(), v2.end(), v2.begin(), 
    addy(std::cos, DEDUCE(std::cos, double))); 
+1

I Sono contemporaneamente impressionato dalla tua abilità simile a MacGyver di piegare un operatore condizionale nella soluzione a questo problema, e sono rimasto sconvolto dal fatto che fosse necessario. :) –

+0

wow, non capisco, ho intenzione di studiare questo ... –

+1

@robert, sentiti libero di fare domande se ci sono alcuni pa non hai capito. Cercherò di dare una spiegazione per loro allora. Assicurati inoltre di leggere la spiegazione di eric nieblers del suo uso di 'operator?' Qui: http://www.artima.com/cppsource/foreach2.html –

4

Lei parla di std::sin nel titolo, ma poi assegnare ::sin.

valarray<double> (*fp)(const valarray<double> &) = std::sin; 

Che dovrebbe funzionare. Nota che dovresti qualificare tutti gli usi di sin, anche se la maggior parte delle implementazioni inserirà il nome nello spazio dei nomi globale anche se includi <cmath> (che è un comportamento non standard).

Modifica: sfortunatamente, sei sfortunato. Lo standard dice su sin(valarray<T> const &) quanto segue (26.3.3.3).

Questa funzione deve restituire un valore che è di tipo T o che può essere inequivocabilmente convertito nel tipo T.

ottimizzazioni eseguite da gcc sono accordati dalla norma. Il codice sopra non è garantito per funzionare.

+0

Non funziona per me su GCC sia. Stesso messaggio di errore :( –

+1

Hai ragione, su GCC infatti fallisce, direi che è un bug però. Lo standard definisce chiaramente 'template valarray sin (const valarray &);' che è certamente convertibile in ' valarray (*) (const valarray &) '. – avakar

+0

sono d'accordo. Sembra una follia GCC :( –

10

26 3,1/3

Qualsiasi funzione che restituisce un valarray è permesso di restituire un oggetto di un altro tipo, fornite tutte le funzioni membro const di valarray sono applicabili anche a questo tipo.

Lo scopo è quello di consentire espressioni modello da utilizzare per ottimizzare il risultato (cioè loop una volta sull'intera matrice facendo ogni volte il calcolo, direttamente assegnando al valarray risultante <> invece di costruire un temporaneo).

z = sin(x+y); 

può essere ottimizzato per

for (i = 0; i < N; ++i) 
    z[i] = sin(x[i] + y[i]); 
+0

+1, questo ha un senso. xD –

Problemi correlati