代码之家  ›  专栏  ›  技术社区  ›  prestokeys

重载的技巧

  •  0
  • prestokeys  · 技术社区  · 11 年前

    考虑以下代码:

    #include <iostream>
    
    class A {
    public:
        template <typename... Args> void execute(Args&&... args) {foo(std::forward<Args>(args)...);}
        template <typename... Args> void doIt(Args&&... args) {bar(std::forward<Args>(args)...);}
    private:
        void foo() {}
        void foo(int) {}
        void foo(int, char) {}
        void foo(bool, int, double) {}
        void bar() {foo();}  // *** Added
        void bar(int) {}
        void bar(int num, char c) {foo(num, c);}  // *** Added
        void bar(bool, int, double) {}
    };
    
    int main() {
        A a;
        a.doIt();
        a.doIt(5,'t');
    }
    

    A::doIt 具有与相同的重载类型 A::execute 并将使用 bar 的重载(对于其中的一些,bar的重载是唯一的),并使用 foo 其他人的超载。为了做到这一点,我简单地添加了 void bar() {foo();} void bar(int num, char c) {foo(num, c);} 。这没那么痛苦,但假设有很多这样的转发要做。并考虑新的过载时的维护问题 doIt 是需要的,并且是新的 食品 为它们定义的重载(容易忘记转发内容)。

    有没有办法去除这些多余的 酒吧 重载(简单地转发到 食品 ),而不是修改当前定义的 doIt(Args&&... args) 函数,以便在不存在此类条过载的情况下调用 食品 的重载?换言之,删除这两个 酒吧 由于 doIt公司 的新定义。

    2 回复  |  直到 11 年前
        1
  •  4
  •   T.C. Yksisarvinen    11 年前

    SFINAE关于 bar(std::forward<Args>(args)...) .

    class A {
    private:
        void foo();
        void foo(int);
        void foo(int, char);
        void foo(bool, int, double);
        void bar(int);
        void bar(bool, int, double);
    
        template <typename... Args> 
        auto doIt_impl(int, Args&&... args) -> decltype(bar(std::forward<Args>(args)...)){
            bar(std::forward<Args>(args)...);
        }
        template <typename... Args> 
        auto doIt_impl(long, Args&&... args) -> void {
            foo(std::forward<Args>(args)...);
        }
    
    public:
        template <typename... Args> void doIt(Args&&... args) {
            doIt_impl(0, std::forward<Args>(args)...);
        }
    };
    

    伪第一参数确保 bar -调用的重载 doIt_impl 如果可行,则首选。此外,需要注意的是,尾随返回类型不会获得类范围查找,因此 doIt_impl文件 必须在声明 酒吧 s

    Demo .

        2
  •  0
  •   prestokeys    11 年前

    由于nwp的提示(尽管我不确定这是否是他的意思),以及T.C.的调试提示,我有了另一种解决方案。但T.C.的解决方案要好得多。

    #include <iostream>
    
    class A_Foo {
    protected:
        virtual void foo() {std::cout << "foo().\n";}
        virtual void foo(int) {std::cout << "foo(int).\n";}
        virtual void foo(int, char) {std::cout << "foo(int, char).\n";}
        virtual void foo(bool, int, double) {std::cout << "foo(bool, int, double).\n";}
    };
    
    class A_Bar : private A_Foo {
    public:
        using A_Foo::foo;  // This is needed.  Else all the declarations of foo in A_Foo are hidden.
        virtual void foo(int) override {std::cout << "bar(int).\n";}
        virtual void foo(bool, int, double) override {std::cout << "bar(bool, int, double).\n";}
    };
    
    class A : private A_Bar {
    public:
        template <typename... Args> void execute(Args&&... args) {
            A_Foo::foo(std::forward<Args>(args)...);
        }
        template <typename... Args> void doIt(Args&&... args) {
            A_Bar::foo(std::forward<Args>(args)...);
        }
    };
    
    int main() {
        A a;
        a.doIt();  // foo().
        a.doIt(5);  // bar(int).
        a.doIt(5,'t');  // foo(int, char).
        a.doIt(true,5,1.8);  // bar(bool, int, double).
    }