What are C++ functors and their uses?

后端 未结 14 2038
花落未央
花落未央 2020-11-21 04:27

I keep hearing a lot about functors in C++. Can someone give me an overview as to what they are and in what cases they would be useful?

14条回答
  •  深忆病人
    2020-11-21 05:05

    Like has been repeated, functors are classes that can be treated as functions (overload operator ()).

    They are most useful for situations in which you need to associate some data with repeated or delayed calls to a function.

    For example, a linked-list of functors could be used to implement a basic low-overhead synchronous coroutine system, a task dispatcher, or interruptable file parsing. Examples:

    /* prints "this is a very simple and poorly used task queue" */
    class Functor
    {
    public:
        std::string output;
        Functor(const std::string& out): output(out){}
        operator()() const
        {
            std::cout << output << " ";
        }
    };
    
    int main(int argc, char **argv)
    {
        std::list taskQueue;
        taskQueue.push_back(Functor("this"));
        taskQueue.push_back(Functor("is a"));
        taskQueue.push_back(Functor("very simple"));
        taskQueue.push_back(Functor("and poorly used"));
        taskQueue.push_back(Functor("task queue"));
        for(std::list::iterator it = taskQueue.begin();
            it != taskQueue.end(); ++it)
        {
            *it();
        }
        return 0;
    }
    
    /* prints the value stored in "i", then asks you if you want to increment it */
    int i;
    bool should_increment;
    int doSomeWork()
    {
        std::cout << "i = " << i << std::endl;
        std::cout << "increment? (enter the number 1 to increment, 0 otherwise" << std::endl;
        std::cin >> should_increment;
        return 2;
    }
    void doSensitiveWork()
    {
         ++i;
         should_increment = false;
    }
    class BaseCoroutine
    {
    public:
        BaseCoroutine(int stat): status(stat), waiting(false){}
        void operator()(){ status = perform(); }
        int getStatus() const { return status; }
    protected:
        int status;
        bool waiting;
        virtual int perform() = 0;
        bool await_status(BaseCoroutine& other, int stat, int change)
        {
            if(!waiting)
            {
                waiting = true;
            }
            if(other.getStatus() == stat)
            {
                status = change;
                waiting = false;
            }
            return !waiting;
        }
    }
    
    class MyCoroutine1: public BaseCoroutine
    {
    public:
        MyCoroutine1(BaseCoroutine& other): BaseCoroutine(1), partner(other){}
    protected:
        BaseCoroutine& partner;
        virtual int perform()
        {
            if(getStatus() == 1)
                return doSomeWork();
            if(getStatus() == 2)
            {
                if(await_status(partner, 1))
                    return 1;
                else if(i == 100)
                    return 0;
                else
                    return 2;
            }
        }
    };
    
    class MyCoroutine2: public BaseCoroutine
    {
    public:
        MyCoroutine2(bool& work_signal): BaseCoroutine(1), ready(work_signal) {}
    protected:
        bool& work_signal;
        virtual int perform()
        {
            if(i == 100)
                return 0;
            if(work_signal)
            {
                doSensitiveWork();
                return 2;
            }
            return 1;
        }
    };
    
    int main()
    {
         std::list coroutineList;
         MyCoroutine2 *incrementer = new MyCoroutine2(should_increment);
         MyCoroutine1 *printer = new MyCoroutine1(incrementer);
    
         while(coroutineList.size())
         {
             for(std::list::iterator it = coroutineList.begin();
                 it != coroutineList.end(); ++it)
             {
                 *it();
                 if(*it.getStatus() == 0)
                 {
                     coroutineList.erase(it);
                 }
             }
         }
         delete printer;
         delete incrementer;
         return 0;
    }
    

    Of course, these examples aren't that useful in themselves. They only show how functors can be useful, the functors themselves are very basic and inflexible and this makes them less useful than, for example, what boost provides.

提交回复
热议问题