2009-08-30 33 views

回答

11

這將編譯。看起來GCC的valarray使用表達式模板來延遲竇的計算。但是這會使sin模板的返回類型不完全是valarray<T>,而是一些奇怪的複雜類型。

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

編輯:見AProgrammer的標準報價爲什麼GCC是罰款這樣做。

編輯:符合標準的解決方法

在嚴格符合標準的方式這樣做沒有__typeof__是有點棘手。您將需要獲得返回類型sin。您可以像這樣使用條件運算符,如Eric Niebler has shown。它的作用是讓sin函數實際上不被調用,但只能進行類型檢查。通過嘗試另一個分支條件運算符來同類型的(這實際上是評估的一個)轉換,我們可以生成一個虛擬參數只是爲了能夠推斷出函數指針的類型:

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

如果您想立即獲取地址,則可以編寫work,以便再次返回fp。現在

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

,你終於可以編寫一個宏來封裝有條件的經營者弄虛作假,當你想要得到任何這樣的數學函數的地址,使用它。

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

要獲取地址,並將它傳遞給一些通用的功能,下面的作品,然後

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

我我同時對你的MacGyver式的能力印象深刻,這種能力可以讓一個條件操作符變成這個問題的解決方案,並且很震驚它有必要這樣做:) – 2009-08-30 14:24:33

+0

哇,我不明白,我將不得不研究這個... – 2009-09-01 01:38:59

+1

@robert,隨意提問,如果有一些pa rts你不明白。那麼我會試着給他們解釋一下。另外請務必閱讀eric nieblers對「運營商?」使用的解釋:http://www.artima.com/cppsource/foreach2.html – 2009-09-01 02:06:08

4

你說的稱號約std::sin,但隨後分配::sin

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

這應該有效。請注意,您應該限定sin的所有用途,儘管大多數實現將名稱注入到全局名稱空間,即使包含<cmath>(這是非標準行爲)。

編輯:不幸的是,你運氣不好。該標準說約sin(valarray<T> const &)以下(26.3.3.3)。

該函數將返回一個值,該值是類型T的或它可以是明確地 轉換爲類型T.與gcc執行

優化由標準理所當然的。上面的代碼不能保證工作。

+0

它不能在GCC爲我工作,要麼。同樣的錯誤信息:( – 2009-08-30 12:38:30

+1

你是對的,在GCC上它確實失敗了,但我認爲這是一個錯誤,標準清楚地定義了'模板 valarray sin(const valarray &);'當然可以轉換爲' valarray (*)(const valarray &)'。 – avakar 2009-08-30 12:42:49

+0

我同意。看起來像一個GCC瘋狂:( – 2009-08-30 12:44:21

10

26 3.1/3

任何函數返回的valarray被允許返回另一個類型的對象, 提供的所有const成員的valarray的功能也適用於這種類型。

的目的是允許使用模板表達式來優化結果(即循環整個陣列做各次的計算在一個時間,直接分配到所得的valarray <>而不是建立一個臨時的)。

z = sin(x+y); 

可以使用__typeof__ GCC擴展進行優化,以

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

+1,這是有道理的xD – 2009-08-30 12:55:15

相關問題