2016-09-19 142 views
2

我試圖寫一個簡單的模板,我可以爲記憶化與功能以一個參數使用:爲什麼模板參數扣除/替換在這裏失敗?

#include <map>   

template <typename F,typename OUT,typename IN> 
OUT memoization(IN in){ 
    static std::map<IN,OUT> memo; 
    static typename std::map<IN,OUT>::iterator found = memo.find(in); 
    if (found != memo.end()) { return found->second; } 
    OUT res = F(in); 
    memo(in) = res; 
    return res; 
} 

double test(double x) { return x*x; } 

int main(){ 
    for (int i=0;i<5;i++){ 
     memoization<test,double,double>(i*0.5); 
    } 
} 

,但我得到的錯誤:

error: no matching function for call to 'memoization(double)'

note: candidate is:

note: template OUT memoization(IN)

note: template argument deduction/substitution failed:

爲什麼這個編譯失敗?

其實我不明白爲什麼模板參數扣除/替換髮生在我指定所有模板參數時。

我使用gcc版本4.7.2(沒有C++ 11啓用)

PS:模板有更多的錯誤,比我第一次意識到,但我離開它是...

+0

'測試'不是一種類型。 'decltype(test)'是。 – MadScientist

回答

5

你的函數模板需要三個類型參數:

template <typename F,typename OUT,typename IN> 
OUT memoization(IN in) { ... } 

你傳遞testFtest不是一種類型,它是一種價值。另外,功能模板中的表達式F(in)由於相同的原因也是錯誤的。


這種方法總的來說很有缺陷,因爲它似乎與實際發生的情況相反。也就是說,這是被記憶的功能,而不是價值。在編譯時也需要函數的值是非常有限的。

更好的方法是將memoization作爲裝飾器對待。那就是:

template <class F> 
Memoized<F> memoize(F f) { 
    return {f}; 
} 

這樣的:

auto memo_test = memoize(test); 
memo_test(0); // performs computation 
memo_test(0); // doesn't perform computation 
memo_test(0); // ditto 

我離開的Memoized<T>實施作爲練習。

+0

ups。是愚蠢的錯誤。但是,我不確定它是否仍能按我的意願工作。這個想法是,對於每個函數,我得到一個不同的模板實例,因此一個單獨的地圖 – user463035818

+0

與您提出的解決方案不是它是我的'測試'和一些'雙富(雙)'相同的模板實例?在這種情況下,我的tempalte方法將是無用的 – user463035818

+0

@ tobi303整個方法是根本上有缺陷,更新答案給你一個更好的方向。 – Barry

0

Why does template argument deduction/substitution fail here?

a。因爲有3個模板參數,只有一個實際參數,所以它們中的兩個是不可延展的(是一個單詞嗎?)。

b。有一個語法錯誤。模板參數F是一個類型,而不是可調用的對象。

如果在預先C++ 11的環境中工作,boostresult_of可以幫助:

#include <map>   
#include <boost/utility/result_of.hpp> 

// 
// now that template arguments are all used when collecting function 
// arguments, the types F and IN can be deduced. 
//  
template <typename F,typename IN> 
typename boost::result_of<F(IN)>::type memoization(F f, IN in) 
{ 
    typedef typename boost::result_of<F(IN)>::type OUT; 
    static std::map<IN,OUT> memo; 
    static typename std::map<IN,OUT>::iterator found = memo.find(in); 
    if (found != memo.end()) { return found->second; } 
    OUT res = f(in); 
    memo[in] = res; 
    return res; 
} 

double test(double x) { return x*x; } 

int main(){ 
    for (int i=0;i<5;i++){ 
     memoization(test, i*0.5); 
    } 
} 
+0

a。不是問題,OP是明確提供所有的模板參數。 – Barry

+0

@巴里所以他是。 yuk :( –

+0

僅供參考:我找到了一個只有C++的解決方案,我不知道如何避免指定所有的模板參數,但它似乎工作。 – user463035818

0

答案已經有了一個令人滿意的答案,但是我很好奇,如果我能得到它運行我的方法(以及純粹的C++ 11)。其實這是可能通過一個函數指針作爲模板參數,一個只是要對模板參數指定此而不是讓它想到一種類型的參數:

#include <iostream> 
#include <map> 
using namespace std; 

template <class T, class R, R (*Func)(T)> 
R memoized(T in) { 
    static std::map<T,R> memo; 
    typename std::map<T,R>::iterator found = memo.find(in); 
    if (found != memo.end()) { return found->second; } 
    std::cout << "not found" << std::endl; 
    R res = Func(in); 
    memo[in] = res; 
    return res; 
} 

double test(double x){return x*x;} 
double test2(double x){return x;} 

int main() { 
    std::cout << memoized<double,double,test>(1) << std::endl; 
    std::cout << memoized<double,double,test>(1) << std::endl; 
    std::cout << memoized<double,double,test>(1) << std::endl; 
    std::cout << std::endl; 
    std::cout << memoized<double,double,test2>(1) << std::endl; 
    std::cout << memoized<double,double,test2>(1) << std::endl; 
    std::cout << memoized<double,double,test2>(1) << std::endl; 

    return 0; 
} 

輸出:

not found 
1 
1 
1 

not found 
1 
1 
1 

還沒當然,如果這是一個好方法,但它似乎有效。