Member-Function Pointers With Default Arguments

后端 未结 4 1497
走了就别回头了
走了就别回头了 2021-01-03 01:03

I am trying to create a pointer to a member function which has default arguments. When I call through this function pointer, I do not want to specify an argument for the de

4条回答
  •  情话喂你
    2021-01-03 01:36

    Task: Suppose you have the following:

    class Thing {
        public:
            void foo (int, double = 3.14) const {std::cout << "Thing::foo(int, double = 3.14) called.\n";}
            void goo (int, double = 1.5) const {std::cout << "Thing::goo(int, double = 1.5) called.\n";}
    };
    
    void function1 (const Thing& thing, int a, int b, double c) {
        // Code A
        thing.foo(a,c);
        // Code B
        thing.foo(b);
        // Code C
    }
    
    void function2 (const Thing& thing, int a, int b, double c) {
        // Code A
        thing.goo(a,c);
        // Code B
        thing.goo(b);
        // Code C
    }
    

    We want to write a helper function to capture function1 and function2 so that the repeated codes A, B, C need not be written twice.

    The following will not compile:

    class Thing {
        public:
            void foo (int, double = 3.14) const {std::cout << "Thing::foo(int, double = 3.14) called.\n";}
            void goo (int, double = 1.5) const {std::cout << "Thing::goo(int, double = 1.5) called.\n";}
    };
    
    void functionHelper (const Thing& thing, int a, int b, double c, void (Thing::*f)(int, double) const) {
        // Code A
        (thing.*f)(a,c);
        // Code B
    //  (thing.*f)(b);  // Won't compile.  Too few arguments passed to (thing.*f), which expects (int, double).
        // Code C   
    }
    
    void function1 (const Thing& thing, int a, int b, double c) {
        functionHelper (thing, a, b, c, &Thing::foo);
    }
    
    void function2 (const Thing& thing, int a, int b, double c) {
        functionHelper (thing, a, b, c, &Thing::goo);
    }
    

    First solution (overload of Thing::foo and Thing::goo):

    #include 
    
    class Thing {
        public:
            void foo (int, double = 3.14) const {std::cout << "Thing::foo(int, double = 3.14) called.\n";}
            void foo_default (int a) const {
                    std::cout << "Thing::foo_default(int) called.\n";
                    foo(a);
            }
            void goo (int, double = 1.5) const {std::cout << "Thing::goo(int, double = 1.5) called.\n";}
            void goo_default (int a) const {
                    std::cout << "Thing::goo_default(int) called.\n";
                    goo(a);
            }
    };
    
    void functionHelper (const Thing& thing, int a, int b, double c,
            void (Thing::*f)(int, double) const, void (Thing::*g)(int) const) {
        // Code A
        (thing.*f)(a,c);
        // Code B
        (thing.*g)(b);  // This will compile now, since (thing.*g) expects int only as argument.
        // Code C   
    }
    
    void function1 (const Thing& thing, int a, int b, double c) {
        functionHelper (thing, a, b, c, &Thing::foo, &Thing::foo_default);
    }
    
    void function2 (const Thing& thing, int a, int b, double c) {
        functionHelper (thing, a, b, c, &Thing::goo, &Thing::goo_default);
    }
    
    int main() {
        Thing thing;
        function1 (thing, 2, 5, 1.8);
        std::cout << '\n';
        function2 (thing, 2, 5, 1.8);
    }
    

    Output:

    Thing::foo(int, double = 3.14) called.
    Thing::foo_default(int) called.
    Thing::foo(int, double = 3.14) called.
    
    Thing::goo(int, double = 1.5) called.
    Thing::goo_default(int) called.
    Thing::goo(int, double = 1.5) called.
    

    Second solution (Wrap Thing::foo and Thing::goo into function objects):

    #include 
    #include 
    
    class Thing {
        public:
            void foo (int, double = 3.14) const {std::cout << "Thing::foo(int, double = 3.14) called.\n";}
            void goo (int, double = 1.5) const {std::cout << "Thing::goo(int, double = 1.5) called.\n";}
            
            class FooOrGoo {
                public: 
                    void operator()(const Thing& thing, int a) const {helper1 (thing, a);}
                    void operator()(const Thing& thing, int a, double b) {helper2 (thing, a, b);}
                    virtual ~FooOrGoo() {std::cout << "Thing::FooOrGoo object destroyed.\n";}
                private:
                    virtual void helper1 (const Thing& thing, int a) const = 0;
                    virtual void helper2 (const Thing& thing, int a, double b) const = 0;
            };
    
            class Foo : public FooOrGoo {
                virtual void helper1 (const Thing& thing, int a) const override {thing.foo(a);}
                virtual void helper2 (const Thing& thing, int a, double b) const override {thing.foo(a, b);}
            };
    
            class Goo : public FooOrGoo {
                virtual void helper1 (const Thing& thing, int a) const override {thing.goo(a);}
                virtual void helper2 (const Thing& thing, int a, double b) const override {thing.goo(a, b);}
            };
    };
    
    void functionHelper (const Thing& thing, int a, int b, double c, std::unique_ptr f) {
        // Code A
        (*f)(thing, a,c);
        // Code B
        (*f)(thing, b);
        // Code C   
    }
    
    void function1 (const Thing& thing, int a, int b, double c) {
        functionHelper (thing, a, b, c, std::unique_ptr(new Thing::Foo));  // 'std::make_unique());' is not supported by GCC 4.8.1.
    }
    
    void function2 (const Thing& thing, int a, int b, double c) {
        functionHelper (thing, a, b, c, std::unique_ptr(new Thing::Goo));  // 'std::make_unique());' is not supported by GCC 4.8.1.
    }
    
    int main() {
        Thing thing;
        function1 (thing, 2, 5, 1.8);
        std::cout << '\n';
        function2 (thing, 2, 5, 1.8);
    }
    

    Output:

    Thing::foo(int, double = 3.14) called.
    Thing::foo(int, double = 3.14) called.
    Thing::FooOrGoo object destroyed.
    
    Thing::goo(int, double = 1.5) called.
    Thing::goo(int, double = 1.5) called.
    Thing::FooOrGoo object destroyed.
    

    Which solution do you think is better? I think the second one is more elegant, but there are more lines of code (I couldn't do it without polymorphism).

提交回复
热议问题