L. *_*uce 0 c++ templates operator-overloading downcast
我有一堂这样的课:
struct Base
{
void aa(int n) const {
std::cout << "aa() " << field*n << std::endl;
}
void bb(int n) const {
std::cout << "bb() " << field*n*2 << std::endl;
}
int field = 2;
};
Run Code Online (Sandbox Code Playgroud)
我希望能够在编译时选择两个实现之一,aa()或者bb(),通过调用操作符方法。就像是:
Base data;
Magic obj(data);
obj.as_AA() * 33; // should call data.aa(33)
obj.as_BB() * 44; // should call data.bb(44)
Run Code Online (Sandbox Code Playgroud)
data不得重复。并且aa()vs的选择bb()必须在编译时解决。
我有一个使用向下转换的解决方案,其行为理论上未定义(我认为)。它构建(使用 g++ 和 clang++)并完美运行,但仍然......
struct AA : public Base
{
void operator*(int n) const {
return Base::aa(n);
}
};
struct BB : public Base
{
void operator*(int n) const {
return Base::bb(n);
}
};
struct Chooser
{
Base obj;
template<typename WHICH> // will be either AA or BB
const WHICH& as() const {
return static_cast<const WHICH&>( obj ); // downcasting
}
};
Run Code Online (Sandbox Code Playgroud)
在main.cpp:
Chooser ch;
ch.as<AA>() * 5; // prints "aa() 10"
ch.as<BB>() * 7; // prints "bb() 28"
Run Code Online (Sandbox Code Playgroud)
我的解决方案有多不可靠?(因为技术上未定义的向下转换)
你看到替代品了吗?
谢谢
ps:当然我可以简单地使用
Base data;
data.aa(33);
data.bb(44);
Run Code Online (Sandbox Code Playgroud)
但我真的想通过相同的名称访问不同的实现,即操作符*
我也可以使用模板化的 operator*Base并具有显式的模板特化,但是这会迫使我使用丑陋的语法,这会使运算符的目的无效:
struct Base {
\\...
template<int N> void operator*(int n) const;
};
template<> void Base::operator*<1>(int n) const {
aa(n);
}
Run Code Online (Sandbox Code Playgroud)
其中需要:
Base data;
data.operator*<1>(44); // ugly
Run Code Online (Sandbox Code Playgroud)
你可以这样写这个Magic类:
struct Magic {
Magic(Base &b) : b(b) {}
Base &b;
struct AA {
Base &b;
void operator*(int n) const {
return b.aa(n);
}
};
struct BB {
Base &b;
void operator*(int n) const {
return b.bb(n);
}
};
AA as_AA() { return AA{b}; }
BB as_BB() { return BB{b}; }
};
Run Code Online (Sandbox Code Playgroud)
这通过使用组合来避免任何继承。此外,没有data对象的副本,因为只对其进行了引用。
现在您可以准确地使用您想要的调用语法,并且它具有正确的行为:
Base data;
Magic obj(data);
obj.as_AA() * 33; // calls data.aa(33) -- prints 66
obj.as_BB() * 44; // calls data.bb(44) -- prints 176
Run Code Online (Sandbox Code Playgroud)
这是一个演示。