考虑以下代码:
#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
的重载(条形码的重载是唯一的并为其他人使用foo
的重载。为此,我只添加了void bar() {foo();}
和void bar(int num, char c) {foo(num, c);}
。这不是那么痛苦,但假设有许多这样的转发要做。当需要doIt
的新重载,并为它们定义新的foo
重载(容易忘记转发内容)时,请考虑维护问题。
有没有办法删除这些额外的bar
重载(只是转发到foo
),而是修改当前定义的doIt(Args&&... args)
函数,以防万一这样的条形过载存在它会调用foo
的重载吗?换句话说,删除我添加的两个bar
重载,并且由于doIt
的新定义,仍然按照预期编译main()。
答案 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
之后。
答案 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).
}