2009-08-30 7 views

Odpowiedz

11

kompiluje to, używając rozszerzenia __typeof__ GCC. Wygląda na to, że GCC ma valarray używa szablonów ekspresji do opóźnienia obliczenia zatoki. Ale to sprawi, że typ zwrotu szablonu sin nie będzie dokładnie taki jak valarray<T>, ale raczej jakiś dziwny typ złożony.

#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: standard cytat Zobacz AProgrammer za dlaczego GCC jest w porządku robić.

Edit: Standardowy obejście zgodny

Robi to bez __typeof__ w ściśle zgodny ze standardem sposób jest nieco skomplikowane. Będziesz musiał uzyskać typ zwrotu sin. Możesz użyć do tego operatora warunkowego, jak Eric Niebler has shown. Działa, ponieważ funkcja sin nie jest wywoływana, ale tylko sprawdzana.Próbując przekształcić drugą gałąź (ten, który jest faktycznie analizowany) operatora warunkowego do tego samego typu, możemy wygenerować manekina parametr, tylko żeby być w stanie wydedukować rodzaj wskaźnika funkcję:

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

Jeśli chcesz od razu uzyskać adres, możesz napisać work, aby ponownie zwrócić fp.

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

Teraz można wreszcie napisać makro do hermetyzacji Operator warunkowy oszustwa i używać go, gdy chcemy uzyskać adres takiej funkcji matematycznej.

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

Aby uzyskać adres i przekazać go do jakiegoś rodzajowego funkcji, następujące prace następnie

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

Jestem jednocześnie pod wrażeniem Twojej zdolności MacGyvera do zginania operatora warunkowego w rozwiązaniu tego problemu i przeraziłem się, że było to konieczne. :) –

+0

wow. Nie rozumiem. Będę musiał to przestudiować ... –

+1

@robert, możesz zadawać pytania, jeśli są jakieś rts, których nie rozumiesz. Postaram się wtedy wytłumaczyć im. Należy również przeczytać wyjaśnienie eric ávlersów dotyczące jego użycia 'operatora?' Tutaj: http://www.artima.com/cppsource/foreach2.html –

4

Mówisz o std::sin w tytule, ale następnie przypisać ::sin.

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

To powinno zadziałać. Zauważ, że powinieneś zakwalifikować wszystkie zastosowania sin, chociaż większość implementacji wprowadzi nazwę do globalnej przestrzeni nazw, nawet jeśli podłączysz <cmath> (to jest zachowanie niestandardowe).

Edytuj: niestety, masz pecha. Standard mówi o następujących sin(valarray<T> const &) (26.3.3.3).

Funkcja ta zwraca wartość, która jest typu T lub które mogą być jednoznacznie przekształcany do typu T.

optymalizacje wykonywane przez gcc są nadawane przez normy. Powyższy kod nie może działać.

+0

To nie działa na mnie na GCC albo. Ten sam komunikat o błędzie :( –

+1

Masz rację, na GCC rzeczywiście się nie powiedzie, powiedziałbym, że to błąd, ale standard wyraźnie definiuje 'szablon valarray sin (const valarray &);' który z pewnością można zamienić na ' valarray (*) (const valarray &) '. – avakar

+0

zgadzam się. Wygląda na szaleństwa GCC :( –

10

26 3,1/3

Każda funkcja przekazujących valarray pozwala się na powrót do obiektu innego typu, przewidziane wszystkie const funkcje składowe valarray także zastosowanie do tego typu.

Celem jest umożliwienie wyrażenia szablon być wykorzystywane do optymalizacji wynik (tj pętli jeden raz na cały szereg robi każdy czas obliczeń, bezpośrednio przypisanie do otrzymanej valarray <> zamiast budować tymczasowe).

z = sin(x+y); 

może zostać zoptymalizowana do

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

+1, to ma sens. i xD –

Powiązane problemy