我有以下类层次结构:
Option (abstract) ^ | +------+-------+ | | + + Something[T] Nothing
实施如下:
class Option {
public:
Option() {};
virtual ~Option() {};
virtual bool nothing() = 0;
};
template <typename T>
class Something : public Option
{
public:
Something(T _value) : value(_value) {};
virtual ~Something() {};
const T value;
virtual bool nothing() {return false;};
};
class Nothing : public Option
{
public:
Nothing() {};
virtual ~Nothing() {};
virtual bool nothing() {return true;};
};
现在,我希望能够编写具有以下签名的函数:
is_nothing: Nothing& => True
is_nothing: Something[T]& => False
我尝试过以下方式使用模板:
template <class T> bool is_nothing(Nothing&) {return true;};
template <class T> bool is_nothing(Something<T> &) {return false;};
当它像这样使用时它确实有效:
is_nothing<int>(Nothing());
is_nothing<int>(Something<int>(4));
但是当这样调用时,由于缺少is_nothing: Option& => bool
而不想编译
is_nothing<int>(an_option())
其中an_option: void => Option&
实际返回Nothing
的实例。所以对我而言,它似乎突然失去了进行多态调用的能力。
使用Option
的代码:
Nothing n;
Option& an_option() {return n;};
int main(int argc,char** argv)
{
is_nothing<int>(an_option());
return 0;
}
请引导我指向正确的方向,因为我觉得这种做法有些不对劲,但我不能完全指责它。
答案 0 :(得分:0)
重载分辨率是根据参数的 static 类型完成的,而不是 dynamic (运行时)类型。当您调用is_nothing<int>(an_option())
时,编译器会将an_option()
解析为返回Option&
的函数,并尝试根据该类型解析,而不是参考绑定的对象的类型。
如果您解释要解决的问题,可能会获得一些在该语言中有效的替代设计。最简单,通用的方法,但同时被认为是代码气味,我不建议使用RTTI信息来推断实际类型。特别是,is_nothing
的实现可以引用Option
并使用RTTI(dynamic_cast
或typeid
)来确定对象的动态类型,并据此采取相应措施
但这是一个糟糕的设计,如果你在什么情况下解释你需要这个和你真正想要解决的问题,你会得到更好的选择。
答案 1 :(得分:0)
您不需要两个单独的功能。 Option
有一个虚拟nothing()
方法,因此您可以创建一个返回nothing()
返回的非模板函数:
bool is_nothing(Option& opt) { return opt.nothing(); }
Nothing n;
Option& an_option() { return n; }
int main(int argc,char** argv)
{
if (is_nothing(an_option()))
...
return 0;
}
当您可以直接致电nothing()
时,这当然是多余的:
Nothing n;
Option& an_option() { return n; }
int main(int argc,char** argv)
{
if (an_option().nothing())
...
return 0;
}