在c++中向类方法传递任意的lamba

Passing an arbitary lamba to a class method in C++

本文关键字:任意 lamba 类方法 c++      更新时间:2023-10-16

我编写了以下人为编写的代码,以便探索一些想法并更多地了解c++。我有一个包含会计信息的Accountant class和一个包含会计向量以及一些方法的Accountants class

代码还使用lambda来查找并打印工资在一定范围内的Accountants

我要做的是创建一个方法,该方法返回基于lambda中任意传递的Accountants对象。

代码如下:

#include <functional>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
// just contains information about an Accountant
class Accountant
{
    private:
        std::string m_name;
        double m_salary;        // yes dealing with currency it's not good to use float types. I KNOW
    public:
        Accountant() {}
        Accountant( std::string _name, double _salary ) : m_name( _name ), m_salary( _salary ) {}
        double salary() const { return( m_salary ); }
        std::string name() const { return( m_name); }
        friend std::ostream& operator << (std::ostream &out, const Accountant &accountant);     
};

std::ostream& operator << (std::ostream &out, const Accountant &accountant)
{
    out << accountant.name() << " " << accountant.salary();
    return(out);
}

// contains a vector of Accountant and performs operations on them
class Accountants
{
    private:
        std::vector<Accountant> m_list;
    public:
        Accountants( std::vector<Accountant> list ) : m_list( list ) {}
        friend std::ostream& operator << (std::ostream &out, const Accountants &m_list);
        // how to implement something like this?
        // 
        Accountants subset( .... some lambda ......   );
};

Accountants Accountants::subset(  .... some lambda .....)
{
    // perform std::find_if() with lambda has parameter and return an Accountants object.
    // what would be even better is have a way to more flexibly and
    // generically pass in lambda so almost any search criteria can be used to
    // return Accountants subset.
}

std::ostream& operator << (std::ostream &out, const Accountants &list)
{
    std::vector<Accountant>::const_iterator iter = list.m_list.begin();
    while (iter != list.m_list.end())
    {
        out << *iter << std::endl;
        ++iter; 
    }
    return(out);
}

int main(int argc, char *argv[])
{
    std::vector<Accountant> emps{{"Josh",2100.0}, {"Kate", 2900.0}, {"Rose",1700.0}};
    Accountants list( emps );
    const auto min_wage = 0.0;
    const auto upper_limit = 2900.0;
    auto lambda = ([=]( Accountant &a ){ return (a.salary() >= min_wage && a.salary() < upper_limit); });

    std::cout << "List of Accountants" << std::endl  << list << std::endl;
    std::cout << "===============================================" << std::endl;

    std::vector<Accountant>::iterator items = std::find_if(emps.begin(), emps.end(), lambda );
    while( items != emps.end() )
    {
        std::cout << (*items).name() << " " << (*items).salary() << std::endl;
        items = std::find_if(++items, emps.end(), lambda );
    }

    // how to implement something like this?
    Accountants inRangeAccountants = list.subset( lambda );

    return( 0 );
}

我可以使用哪些方法,哪些代码样本,如果可能的话,创建一个方法,如:

Accountants inRangeAccountants = list.subset( lambda );   

使得"lambda"可以是任意的?我们的想法是能够使用subset()方法返回一个Accountants对象,该对象包含与lambda中指定的搜索条件相似的项。类似于main()中的代码,返回特定工资范围内的会计人员。

我认为模板和std::函数将需要使用?

任何帮助与代码示例将不胜感激。

可以这么简单:

template <typename Lambda>
Accountants subset(Lambda func)
{
    /* your code that calls func() */
}

如果你想要的只是一个lambda参数值,你不需要使用std::function。如果向subset传递一个不能作为函数调用的参数,代码将无法编译。

您的subset函数应该接受任何类型的可调用对象,因此将其作为成员函数模板。然后使用copy_if将匹配谓词的Accountant复制到结果中。

template<typename Callable>
Accountants subset(Callable&& c)
{
  std::vector<Accountant> result;
  std::copy_if(m_list.begin(), m_list.end(), 
               std::back_inserter(result), std::forward<Callable>(c));
  return result;
}

现场演示

最简单的方法是使用std::function<bool( const Account &)>作为参数。在这种情况下,您将能够传递不同的lambdas。

例如

Accountants Accountants::subset( std::function<bool( const Account &)> f ) const;

你可以像下面这样调用这个方法

Accounts a1( /* some arguments */ );
Accounts a2 = a1.subset( []( const Account &a ) { return a.salary() < 5000; } );

Accounts a2 = a1.subset( []( const Account &a ) { return a.name().front() == 'A'; } );

对于std::function,你可以使用函数,lambda,函数对象。因此不需要使用模板。