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

还没当然,如果这是一个好方法,但它似乎有效。

相关问题