为了账号安全,请及时绑定邮箱和手机立即绑定

当涉及std:function或lambda函数时,C+11不推断类型

当涉及std:function或lambda函数时,C+11不推断类型

C++ C
缥缈止盈 2019-07-12 15:02:50
当涉及std:function或lambda函数时,C+11不推断类型当我定义这个函数时,template<class A>set<A> test(const set<A>& input) {     return input;}我可以用test(mySet)在代码的其他地方,无需显式定义模板类型。但是,当我使用以下函数时:template<class A>set<A> filter(const set<A>& input,function<bool(A)> compare) {     set<A> ret;     for(auto it = input.begin(); it != input.end(); it++) {         if(compare(*it)) {             ret.insert(*it);         }     }     return ret;}当我调用此函数时,使用filter(mySet,[](int i) { return i%2==0; });我得到以下错误:错误:没有调用‘filter’的匹配函数(std:set&,main():)然而,所有这些版本做工作:std::function<bool(int)> func = [](int i) { return i%2 ==0; };set<int> myNewSet = filter(mySet,func); set<int> myNewSet = filter<int>(mySet,[](int i) { return i%2==0; }); set<int> myNewSet = filter(mySet,function<bool(int)>([](int i){return i%2==0;}));当我将lambda函数直接放入表达式而不直接创建std::function?编辑:根据注释中Luc Danton的建议,这里有一个替代函数,它不需要显式传递模板。template<class A,class CompareFunction>set<A> filter(const set<A>& input,CompareFunction compare) {     set<A> ret;     for(auto it = input.begin(); it != input.end(); it++) {         if(compare(*it)) {             ret.insert(*it);         }     }     return ret;}这可以被set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; });而不需要模板。编译器甚至可以在某种程度上猜测返回类型,使用新的Dectype关键字和使用新函数返回类型语法。下面是一个示例,它使用一个过滤函数和一个基于值生成键的函数将集合转换为映射:template<class Value,class CompareType,class IndexType>auto filter(const set<Value>& input,CompareType compare,IndexType index) ->  map<decltype(index(*(input.begin()))),Value> {     map<decltype(index(*(input.begin()))),Value> ret;     for(auto it = input.begin(); it != input.end(); it++) {         if(compare(*it)) {             ret[index(*it)] = *it;         }     }     return ret;}也可以在不直接使用模板的情况下调用它,如map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });
查看完整描述

3 回答

?
慕姐8265434

TA贡献1813条经验 获得超2个赞

别管你的案子了。因为这太复杂了,无法进行分析。

以这个简单的例子为例:

 template<typename T>
 struct X 
 {
     X(T data) {}
 };

 template<typename T>
 void f(X<T> x) {}

现在打电话f作为:

 f(10);

在这里你可能会想T将被推断为int 因此,上述函数调用应该可以工作。但事实并非如此。为了保持简单,想象一下另一个构造函数int作为:

 template<typename T>
 struct X 
 {
     X(T data) {}
     X(int data) {} //another constructor
 };

现在呢T当我写的时候f(10)?井,T任何类型。

请注意,可能还有许多其他这样的情况。以这种专业化为例:

 template<typename T>
 struct X<T*>         //specialized for pointers
 {
    X(int data) {}; 
 };

现在呢T应推断为呼叫f(10)?现在似乎更难了。

因此,它是不可还原的上下文,这解释了为什么您的代码不能工作。std::function这是一个相同的情况-只是表面看上去很复杂。请注意兰巴斯非类型std::function-它们基本上是编译器生成类的实例(即它们是编译器生成的类的函子异类类型比std::function).


查看完整回答
反对 回复 2019-07-12
?
芜湖不芜

TA贡献1796条经验 获得超7个赞

如果我们有:

template <typename R, typename T>int myfunc(std::function<R(T)> lambda){
  return lambda(2);}int r = myfunc([](int i) { return i + 1; });

它不会编译。但如果你之前声明:

template <typename Func, typename Arg1>static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr) -> decltype((*func)(*arg1));
template <typename Func>int myfunc(Func lambda){
  return myfunc<int, decltype(getFuncType<Func, int>())>(lambda);}

您可以使用lambda参数毫无问题地调用函数。

这里有两个新代码。

首先,我们有一个函数声明,它仅适用于根据给定的模板参数返回一个旧的函数指针类型:

template <typename Func, typename Arg1>static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr) -> decltype((*func)(*arg1)) {};

其次,我们有一个函数,它接受一个模板参数来构建我们期望的lambda类型,调用‘getFuncType’:

template <typename Func>int myfunc(Func lambda){
  return myfunc<int, decltype(getFuncType<Func, int>())>(lambda);}

有了正确的模板参数,现在我们可以调用真正的‘myfunc’。完整的代码是:

template <typename R, typename T>int myfunc(std::function<R(T)> lambda){
  return lambda(2);}template <typename Func, typename Arg1>static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr) -> 
  decltype((*func)(*arg1)) {};template <typename Func>int myfunc(Func lambda){
  return myfunc<int, decltype(getFuncType<Func, int>())>(lambda);}int r = myfunc([](int i) { return i + 1; });

您可以为“getFuncType”声明与lambda参数匹配的任何重载。例如:

template <typename Func, typename Arg1, typename Arg2>static auto getFuncType(Func* func = nullptr, Arg1* arg1 = nullptr, Arg2*
 arg2 = nullptr) -> decltype((*func)(*arg1, *arg2)) {};



查看完整回答
反对 回复 2019-07-12
  • 3 回答
  • 0 关注
  • 546 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信