2009-08-30 6 views

Répondre

11

Cette compile, en utilisant l'extension __typeof__ GCC. On dirait que le valarray de GCC utilise des modèles d'expression pour retarder le calcul du sinus. Mais cela rendra le type de retour du modèle sin pas exactement valarray<T>, mais plutôt un type complexe bizarre.

#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: Voir AProgrammer pourquoi GCC est citation standard bien faire.

Edit: solution conforme à la norme

Faire cela sans __typeof__ d'une manière conforme strictement standard est un peu délicat. Vous devrez obtenir le type de retour sin. Vous pouvez utiliser l'opérateur conditionnel pour cela, comme Eric Niebler has shown. Cela fonctionne en ayant la fonction sin non appelée réellement, mais seulement vérifiée par type.En essayant de convertir l'autre branche (celle qui est en fait évalué) de l'opérateur conditionnel à ce même type, nous pouvons générer un paramètre fictif juste pour être en mesure de déduire le type de pointeur de fonction:

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

Si vous souhaitez obtenir l'adresse immédiatement, vous pouvez écrire work pour qu'il renvoie à nouveau fp.

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

Maintenant, vous pouvez enfin écrire une macro pour résumer la supercherie de l'opérateur conditionnel, et l'utiliser quand vous voulez obtenir l'adresse d'une telle fonction mathématique.

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

Pour obtenir l'adresse et le transmettre à une fonction générique, les œuvres suivantes, alors

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 Je suis simultanément impressionné par votre capacité de MacGyver à plier un opérateur conditionnel dans la solution à ce problème, et horrifié qu'il était nécessaire de le faire. :) –

+0

wow, je ne comprends pas, je vais devoir étudier cette ... –

+1

@robert, n'hésitez pas à poser des questions s'il y a quelques pa tu ne comprends pas. Je vais essayer de leur donner une explication à ce moment-là. Assurez-vous également de lire l'explication de eric nieblers sur son utilisation de 'operator?' Ici: http://www.artima.com/cppsource/foreach2.html –

4

Vous parlez std::sin dans le titre, mais attribuez ::sin.

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

Cela devrait fonctionner. Notez que vous devez qualifier toutes les utilisations de sin, bien que la plupart des implémentations injectent le nom dans l'espace de noms global même si vous incluez <cmath> (comportement non standard).

Edit: malheureusement, vous n'avez pas de chance. La norme dit à propos de sin(valarray<T> const &) ce qui suit (26.3.3.3).

Cette fonction retourne une valeur qui est de type T ou qui peut être sans ambiguïté convertie en type T.

Optimisations effectuées par gcc sont accordées par la norme. Le code ci-dessus n'est pas garanti pour fonctionner.

+0

Il ne fonctionne pas pour moi sur GCC soit. Même message d'erreur :( –

+1

Vous avez raison, sur GCC, il échoue en effet, je dirais que c'est un bug .. La norme définit clairement 'template valarray sin (const valarray &);' qui est certainement convertible en ' valarray (*) (const valarray &) '. – avakar

+0

Je suis d'accord. on dirait une folie GCC :( –

10

26 3,1/3

Toute fonction retournant un valarray est autorisé à renvoyer un objet d'un autre type, fourni toutes les fonctions membres const de valarray sont également applicables à ce type.

Le but est de permettre à des expressions de modèle à utiliser pour optimiser le résultat (à savoir en boucle une fois sur la totalité du tableau faisant chaque fois le calcul, en affectant directement au valarray résultant <> au lieu de construire un temporaire).

z = sin(x+y); 

peut être optimisé pour

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

1, qui a du sens. xD –

Questions connexes