猿问

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

当涉及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); });


慕森卡
浏览 577回答 3
3回答

缥缈止盈

别管你的案子了。因为这太复杂了,无法进行分析。以这个简单的例子为例:&nbsp;template<typename&nbsp;T> &nbsp;struct&nbsp;X&nbsp; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X(T&nbsp;data)&nbsp;{} &nbsp;}; &nbsp;template<typename&nbsp;T> &nbsp;void&nbsp;f(X<T>&nbsp;x)&nbsp;{}现在打电话f作为:&nbsp;f(10);在这里你可能会想T将被推断为int&nbsp;和因此,上述函数调用应该可以工作。但事实并非如此。为了保持简单,想象一下另一个构造函数int作为:&nbsp;template<typename&nbsp;T> &nbsp;struct&nbsp;X&nbsp; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X(T&nbsp;data)&nbsp;{} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X(int&nbsp;data)&nbsp;{}&nbsp;//another&nbsp;constructor &nbsp;};现在呢T当我写的时候f(10)?井,T能任何类型。请注意,可能还有许多其他这样的情况。以这种专业化为例:&nbsp;template<typename&nbsp;T> &nbsp;struct&nbsp;X<T*>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//specialized&nbsp;for&nbsp;pointers &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;X(int&nbsp;data)&nbsp;{};&nbsp; &nbsp;};现在呢T应推断为呼叫f(10)?现在似乎更难了。因此,它是不可还原的上下文,这解释了为什么您的代码不能工作。std::function这是一个相同的情况-只是表面看上去很复杂。请注意兰巴斯非类型std::function-它们基本上是编译器生成类的实例(即它们是编译器生成的类的函子异类类型比std::function).

aluckdog

如果我们有:template&nbsp;<typename&nbsp;R,&nbsp;typename&nbsp;T>int&nbsp;myfunc(std::function<R(T)>&nbsp;lambda){ &nbsp;&nbsp;return&nbsp;lambda(2);}int&nbsp;r&nbsp;=&nbsp;myfunc([](int&nbsp;i)&nbsp;{&nbsp;return&nbsp;i&nbsp;+&nbsp;1;&nbsp;});它不会编译。但如果你之前声明:template&nbsp;<typename&nbsp;Func,&nbsp;typename&nbsp;Arg1>static&nbsp;auto&nbsp;getFuncType(Func*&nbsp;func&nbsp;=&nbsp;nullptr,&nbsp;Arg1*&nbsp;arg1&nbsp;=&nbsp;nullptr)&nbsp;->&nbsp;decltype((*func)(*arg1)); template&nbsp;<typename&nbsp;Func>int&nbsp;myfunc(Func&nbsp;lambda){ &nbsp;&nbsp;return&nbsp;myfunc<int,&nbsp;decltype(getFuncType<Func,&nbsp;int>())>(lambda);}您可以使用lambda参数毫无问题地调用函数。这里有两个新代码。首先,我们有一个函数声明,它仅适用于根据给定的模板参数返回一个旧的函数指针类型:template&nbsp;<typename&nbsp;Func,&nbsp;typename&nbsp;Arg1>static&nbsp;auto&nbsp;getFuncType(Func*&nbsp;func&nbsp;=&nbsp;nullptr,&nbsp;Arg1*&nbsp;arg1&nbsp;=&nbsp;nullptr)&nbsp;->&nbsp;decltype((*func)(*arg1))&nbsp;{};其次,我们有一个函数,它接受一个模板参数来构建我们期望的lambda类型,调用‘getFuncType’:template&nbsp;<typename&nbsp;Func>int&nbsp;myfunc(Func&nbsp;lambda){ &nbsp;&nbsp;return&nbsp;myfunc<int,&nbsp;decltype(getFuncType<Func,&nbsp;int>())>(lambda);}有了正确的模板参数,现在我们可以调用真正的‘myfunc’。完整的代码是:template&nbsp;<typename&nbsp;R,&nbsp;typename&nbsp;T>int&nbsp;myfunc(std::function<R(T)>&nbsp;lambda){ &nbsp;&nbsp;return&nbsp;lambda(2);}template&nbsp;<typename&nbsp;Func,&nbsp;typename&nbsp;Arg1>static&nbsp;auto&nbsp;getFuncType(Func*&nbsp;func&nbsp;=&nbsp;nullptr,&nbsp;Arg1*&nbsp;arg1&nbsp;=&nbsp;nullptr)&nbsp;->&nbsp; &nbsp;&nbsp;decltype((*func)(*arg1))&nbsp;{};template&nbsp;<typename&nbsp;Func>int&nbsp;myfunc(Func&nbsp;lambda){ &nbsp;&nbsp;return&nbsp;myfunc<int,&nbsp;decltype(getFuncType<Func,&nbsp;int>())>(lambda);}int&nbsp;r&nbsp;=&nbsp;myfunc([](int&nbsp;i)&nbsp;{&nbsp;return&nbsp;i&nbsp;+&nbsp;1;&nbsp;});您可以为“getFuncType”声明与lambda参数匹配的任何重载。例如:template&nbsp;<typename&nbsp;Func,&nbsp;typename&nbsp;Arg1,&nbsp;typename&nbsp;Arg2>static&nbsp;auto&nbsp;getFuncType(Func*&nbsp;func&nbsp;=&nbsp;nullptr,&nbsp;Arg1*&nbsp;arg1&nbsp;=&nbsp;nullptr,&nbsp;Arg2* &nbsp;arg2&nbsp;=&nbsp;nullptr)&nbsp;->&nbsp;decltype((*func)(*arg1,&nbsp;*arg2))&nbsp;{};
随时随地看视频慕课网APP
我要回答