我正在尝试编写一个简单的模板,我可以使用带有单个参数的函数进行memoization:
#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);
}
}
但我得到错误:
错误:没有用于调用&#39; memoization(double)&#39;
的匹配函数注意:候选人是:
注意:模板OUT memoization(IN)
注意:模板参数扣除/替换失败:
为什么无法编译?
实际上,当我指定所有模板参数时,我根本不明白为什么模板参数推断/替换正在发生。
我正在使用gcc版本4.7.2(未启用C ++ 11)
PS:模板比我最初意识到的错误多得多,但我保留原样......
答案 0 :(得分:5)
您的功能模板需要三个类型参数:
template <typename F,typename OUT,typename IN>
OUT memoization(IN in) { ... }
您正在test
传递F
。 test
不是一种类型,它是一种价值。此外,由于同样的原因,函数模板中的表达式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>
的实施作为练习。
答案 1 :(得分:0)
为什么模板参数推断/替换在这里失败?
a。因为有3个模板参数而且只有一个实际参数,所以其中两个是不可知的(是一个单词?)。 击>
湾存在语法错误。模板参数F是一种类型,而不是可调用对象。
如果必须在pre-c ++ 11环境中运行,boost
result_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);
}
}
答案 2 :(得分:0)
答案已经得到了满意的答案,但是我很好奇我是否可以使用我的方法运行(并且纯粹使用C ++ 11之前)。实际上可以将函数指针作为模板参数传递,只需在模板参数上指定它而不是让它期望类型参数:
start_urls
输出:
#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;
}
仍不确定这是否是一种好方法,但似乎有效。