当前位置: 首页 > 知识库问答 >
问题:

为什么模板参数推导/替换在此失败?

龙霖
2023-03-14

我正在尝试编写一个简单的模板,我可以使用该模板对带有单个参数的函数进行记忆:

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

但我得到了一个错误:

错误:没有匹配函数来调用“备忘录(双精度)”

注:候选人是:

注意:模板OUT记忆(IN)

注意:模板参数扣除/替换失败:

为什么编译失败?

实际上,当我指定所有模板参数时,我不明白为什么模板参数推导/替换会发生。

我使用的是gcc版本4.7.2(未启用C 11)

PS:模板的错误比我最初意识到的要多得多,但我保持原样...

共有3个答案

商璞
2023-03-14

答案已经得到了一个令人满意的答案,但是我很好奇我是否能让它与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

仍然不确定这是否是一个好的方法,但它似乎有效。

鄂坚
2023-03-14

为什么模板参数推导/替换在此失败?

<罢工> 答。因为有3个模板参数,只有一个实际参数,所以其中两个是可低估的(那是一个词吗?)。

b、 出现语法错误。模板参数F是一种类型,而不是可调用对象。

如果这必须在c11之前的环境中工作,boopresult_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);
    }
}
曾英睿
2023-03-14

函数模板采用三种类型的参数

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

您正在为F传递testtest不是类型,而是值。此外,函数模板中的表达式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

我把的实现留在记忆中

 类似资料:
  • 这些代码如下: 使用G++4.8.2错误信息编译:

  • 我已经编写了一个具有递归评估的可变参数模板函数。对于最后一个参数,我在没有可变参数包的情况下实现了专业化,并且一切正常。 现在我想把可变函数参数转换成模板参数。 这是我的尝试: gcc和clang报告了一个模糊的过载,并且无法使用空参数包在“专业化”和“可变参数”之间做出决定。 我尝试删除特化并检查可变参数模板中的包大小,但是如果没有特化,编译器就无法推断出参数“p”。

  • 我试图使用一对两个迭代器同时迭代两个无序映射。如果我们迭代两个向量,这种方法可以很好地工作; 掠夺。cpp:在函数“int main()”中:prog。cpp:18:70:错误:调用'std::pair,std::_ cx11::basic_string时没有匹配函数 ::对(std::无序_ map,std::_cx11::基本_string

  • 但是这个技巧在零数组的情况下不起作用。为什么下面的代码不正确?例如,联机编译器ideone打印以下错误消息: 错误:调用'size_of_array(int[0])' std::size_t num=size_of_array(arr)没有匹配的函数;

  • 我创建了一个模板类,其中构造函数采用std::function对象。第一个模板参数指示该函数的返回值。第二个参数定义该函数的参数类型。 关于使用函数std::function 它尝试使用基本版本。但第二个参数当然丢失了。如果我指定它编译的模板参数。 那么,为什么选择基本模板作为executorSpecialization2呢?甚至可以在这里对void使用类型推断,而不需要传递模板参数吗? 谢啦

  • 在传递函数时,我遇到了这个模板演绎/替换问题。有人可以帮忙吗,我非常感谢: 以下是编译代码时的错误: 示例.cpp:在 'bool Region::setAllValues(D) 的实例化中