2016-09-19 8 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

'test'はタイプではありません。 'decltype(test)'はです。 – MadScientist

答えて

5

あなたがFためtestに渡してい

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

:あなたの関数テンプレートは3つの タイプの引数を取ります。 testは型ではなく、値です。また、関数テンプレート内の式 F(in)も同じ理由で間違っています。


このアプローチは、実際に起こっていることからかなり後ろ向きに見えるため、一般的にかなり欠陥があります。すなわち、値ではなくメモである関数です。また、コンパイル時に関数の値を要求することはかなり限定的です。

メモ帳をデコレータとして扱う方がよいでしょう。それは次のとおりです。私は運動としてMemoized<T>の実装を残す

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

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

ように。

+0

アップ。ええ、ばかな間違い。しかし、私が望むようにそれがまだ機能するかどうかはわかりません。アイデアは、各関数のために私はテンプレートの異なるインスタンス化を取得し、それゆえ個別のマップ – user463035818

+0

はあなたの提案された解決策では、それは私の 'test'と' double foo(double) 'のための同じテンプレートインスタンス化ではありませんか?この場合、私の一時的なアプローチはむしろ役に立たないでしょう。 – user463035818

+0

@ tobi303全体のアプローチは基本的に欠陥があり、あなたに良い方向を与えるための答えを更新しました。 – Barry

0

Why does template argument deduction/substitution fail here?

a。 3つのテンプレート引数と1つの実際の引数しかないので、それらのうちの2つはundeduce-ableです(それは単語ですか?)。

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

@Barryだから彼です。 yuk :( –

+0

FYI:C++のみのソリューションが見つかりました。すべてのテンプレートパラメータを指定しないようにする方法はわかりませんが、うまくいくようです。 – user463035818

0

、私はそれを得ることができればしかし、私は興味がありました私のアプローチで(そして純粋にpre 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 

ありませんこれが良いアプローチであるかどうかは確かですが、うまくいくようです。

関連する問題