将任意lambda传递给C ++中的类方法

时间:2014-06-19 20:48:20

标签: c++ templates c++11 lambda

我编写了以下设计代码,以便探索一些想法并了解有关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 :: function需要使用吗?

任何有关代码示例的帮助都将不胜感激。

3 个答案:

答案 0 :(得分:4)

可以这么简单:

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

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

答案 1 :(得分:2)

最简单的方法是使用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,函数对象。所以不需要使用模板。

答案 2 :(得分:2)

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

Live demo