过度伎俩

时间:2015-08-05 18:47:47

标签: c++ templates overloading

考虑以下代码:

#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::doItA::execute具有相同的重载类型,并且会为其中一些使用bar的重载(条形码的重载是唯一的并为其他人使用foo的重载。为此,我只添加了void bar() {foo();}void bar(int num, char c) {foo(num, c);}。这不是那么痛苦,但假设有许多这样的转发要做。当需要doIt的新重载,并为它们定义新的foo重载(容易忘记转发内容)时,请考虑维护问题。

有没有办法删除这些额外的bar重载(只是转发到foo),而是修改当前定义的doIt(Args&&... args)函数,以防万一这样的条形过载存在它会调用foo的重载吗?换句话说,删除我添加的两个bar重载,并且由于doIt的新定义,仍然按照预期编译main()。

2 个答案:

答案 0 :(得分:4)

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的声明必须在声明bar之后。

Demo

答案 1 :(得分:0)

感谢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).
}