当涉及std :: function或lambda函数时,C ++ 11不会推断类型 [英] C++11 does not deduce type when std::function or lambda functions are involved

查看:163
本文介绍了当涉及std :: function或lambda函数时,C ++ 11不会推断类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我定义此函数时,

  template< class A> 
set< A> test(const set< A& input){
return input;
}



我可以使用 / code>在代码中的其他地方,而无需显式定义模板类型。但是,当我使用以下函数:

  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 );
}
}
return ret;
}



当我使用 filter [](int i){return i%2 == 0;});
我得到以下错误:

 错误:没有匹配函数调用'filter(std :: set< int>& main()::< lambda(int)>)'



但是,所有这些版本都会工作:

  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



EDIT: >

根据Luc Danton在意见中的建议,这里是我之前的函数的替代方法,不需要显式传递模板。

 模板< 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 );
}
}
return ret;
}

这可以通过 set< int& result = filter(myIntSet,[](int i){i%2 == 0;});

$


$ b $ p <编译器甚至可以在一定程度上猜测返回类型,使用新的decltype关键字并使用新的函数返回类型语法。下面是一个使用一个过滤函数和一个基于值生成键的函数将集合转换为地图的示例:

  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;
}
}
return ret;
}

也可以不使用模板直接调用

  map< string,int> s = filter(myIntSet,[](int i){return i%2 == 0;},[](int i){return toString(i);}); 


解决方案

问题在于lambdas的性质。它们是根据标准具有固定属性集的函数对象,但它们不是函数。该标准确定lambdas可以转换为 std :: function<> ,具有确切的参数类型,如果它们没有状态,函数指针。

但这并不意味着一个lambda是一个 std :: function 也不是一个函数指针。它们是实现 operator()的唯一类型。



另一方面,类型扣除只会推导出精确类型,没有转换(const / volatile限定除外)。因为lambda不是 std :: function ,编译器不能推导调用中的类型: filter(mySet,[](int i){返回i%2 == 0;}); 为任何 std :: function<> 实例化。



作为其他例子,在第一个,你将lambda转换为函数类型,然后传递。编译器可以推导出类型,如在第三个例子中, std :: function 是相同类型的右值(临时)。



如果你向模板提供了实例化类型 int ,第二个工作示例,演绎不会发挥,编译器将使用类型,然后将lambda转换为适当的类型。


When I define this function,

template<class A>
set<A> test(const set<A>& input) {
    return input;
}

I can call it using test(mySet) elsewhere in the code without having to explicitly define the template type. However, when I use the following function:

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

When I call this function using filter(mySet,[](int i) { return i%2==0; }); I get the following error:

error: no matching function for call to ‘filter(std::set<int>&, main()::<lambda(int)>)’

However, all of these versions do work:

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

Why is c++11 unable to guess the template type when I put the lambda function directly inside the expression without directly creating a std::function?

EDIT:

Per advice of Luc Danton in the comments, here is an alternative to the function I had earlier that does not need the templates to be passed explicitly.

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

This can be called by set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; }); without needing the template.

The compiler can even guess the return types to some extent, using the new decltype keyword and using the new function return type syntax. Here is an example that converts a set to a map, using one filtering function and one function that generates the keys based on the values:

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

It can also be called without using the template directly, as

map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); });

解决方案

The issue is on the nature of lambdas. They are function objects with a fixed set of properties according to the standard, but they are not a function. The standard determines that lambdas can be converted into std::function<> with the exact types of arguments and, if they have no state, function pointers.

But that does not mean that a lambda is a std::function nor a function pointer. They are unique types implementing operator().

Type deduction, on the other hand, will only deduce exact types, with no conversions (other than const/volatile qualifications). Because the lambda is not a std::function the compiler cannot deduce the type in the call: filter(mySet,[](int i) { return i%2==0; }); to be any std::function<> instantiation.

As of the other examples, in the first one you convert the lambda to the function type, and then pass that. The compiler can deduce the type there, as in the third example where the std::function is an rvalue (temporary) of the same type.

If you provide the instantiating type int to the template, second working example, deduction does not come into play the compiler will use the type and then convert the lambda to the appropriate type.

这篇关于当涉及std :: function或lambda函数时,C ++ 11不会推断类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆