簡體   English   中英

為什么模板參數推導/替換在這里失敗?

[英]Why does template argument deduction/substitution fail here?

我正在嘗試編寫一個簡單的模板,該模板可用於帶有單個參數的函數的備注:

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

但是我得到了錯誤:

錯誤:沒有匹配的函數可調用“ memoization(double)”

注意:候選人是:

注意:模板OUT備注(IN)

注意:模板參數推導/替換失敗:

為什么無法編譯?

實際上,當我指定所有模板參數時,我根本不理解為什么模板參數推導/替換完全發生。

我正在使用gcc版本4.7.2(未啟用C ++ 11)

PS:該模板的錯誤比我最初意識到的要多得多,但我將其保留為原樣...

您的函數模板帶有三個類型參數:

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

您正在通過F test test不是一種類型,而是一種價值。 同樣,出於相同的原因,函數模板中的表達式F(in)是錯誤的。


通常,這種方法存在很大的缺陷,因為它似乎比實際發生的事情倒退了很多。 即,它是要記憶的功能,而不是值。 在編譯時也需要函數值是相當有限的。

更好的方法是將記憶作為裝飾器。 那是:

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>的實現Memoized<T>練習。

為什么模板參數推導/替換在這里失敗?

一種。 因為有3個模板參數,而只有一個實際參數,所以其中兩個是不可推論的(是一個單詞嗎?)。

存在語法錯誤。 模板參數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);
    }
}

答案已經有了令人滿意的答案,但是我很好奇我是否可以使用我的方法(以及純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

仍然不確定這是否是一種好方法,但似乎可行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM