What are C++ functors and their uses?

后端 未结 14 1497
花落未央
花落未央 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<Functor> 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<Functor>::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<BaseCoroutine* > coroutineList;
         MyCoroutine2 *incrementer = new MyCoroutine2(should_increment);
         MyCoroutine1 *printer = new MyCoroutine1(incrementer);
    
         while(coroutineList.size())
         {
             for(std::list<BaseCoroutine *>::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.

    0 讨论(0)
  • 2020-11-21 05:06

    Name "functor" has been traditionaly used in category theory long before C++ appeared on the scene. This has nothing to do with C++ concept of functor. It's better to use name function object instead of what we call "functor" in C++. This is how other programming languages call similar constructs.

    Used instead of plain function:

    Features:

    • Function object may have state
    • Function object fits into OOP (it behaves like every other object).

    Cons:

    • Brings more complexity to the program.

    Used instead of function pointer:

    Features:

    • Function object often may be inlined

    Cons:

    • Function object can not be swapped with other function object type during runtime (at least unless it extends some base class, which therefore gives some overhead)

    Used instead of virtual function:

    Features:

    • Function object (non-virtual) doesn't require vtable and runtime dispatching, thus it is more efficient in most cases

    Cons:

    • Function object can not be swapped with other function object type during runtime (at least unless it extends some base class, which therefore gives some overhead)
    0 讨论(0)
提交回复
热议问题