导致这种超载解决问题的原因是什么?
我有一个程序,其中有很多嵌套的 if/switch 语句,这些语句在多个地方重复。我尝试将其提取出来并将开关放入模板方法类中,然后允许客户端重载他们想要使用重载专门处理的开关分支:
class TraitsA {};
class TraitsB : public TraitsA {};
class Foo
{
bool traitsB;
public:
// Whether or not a Foo has traitsB is determined at runtime. It is a
// function of the input to the program and therefore cannot be moved to
// compile time traits (like the Iterators do)
Foo() : traitsB(false) {}
virtual ~Foo() {}
bool HasTraitsB() const { return traitsB; }
void SetTraitsB() { traitsB = true; }
};
class SpecificFoo : public Foo
{
};
template <typename Client> //CRTP
class MergeFoo
{
protected:
Foo DoMerge(Foo&, const Foo&, int, TraitsA)
{
// Do things to merge generic Foo
}
public:
// Merge is a template method that puts all the nasty switch statements
// in one place.
// Specific mergers implement overloads of DoMerge to specify their
// behavior...
Foo Merge(Foo* lhs, const Foo* rhs, int operation)
{
const Client& thisChild = *static_cast<const Client*>(this);
SpecificFoo* lhsSpecific = dynamic_cast<SpecificFoo*>(lhs);
const SpecificFoo* rhsSpecific = dynamic_cast<const SpecificFoo*>(rhs);
// In the real code these if's are significantly worse
if (lhsSpecific && rhsSpecific)
{
if (lhs->HasTraitsB())
{
return thisChild.DoMerge(*lhsSpecific,
*rhsSpecific,
operation,
TraitsB());
}
else
{
return thisChild.DoMerge(*lhsSpecific,
*rhsSpecific,
operation,
TraitsA());
}
}
else
{
if (lhs->HasTraitsB())
{
return thisChild.DoMerge(*lhs, *rhs, operation, TraitsB());
}
else
{
return thisChild.DoMerge(*lhs, *rhs, operation, TraitsA());
}
}
}
};
class ClientMergeFoo : public MergeFoo<ClientMergeFoo>
{
friend class MergeFoo<ClientMergeFoo>;
Foo DoMerge(SpecificFoo&, const SpecificFoo&, int, TraitsA)
{
// Do things for specific foo with traits A or traits B
}
};
class ClientMergeFooTwo : public MergeFoo<ClientMergeFoo>
{
friend class MergeFoo<ClientMergeFooTwo>;
Foo DoMerge(SpecificFoo&, const SpecificFoo&, int, TraitsB)
{
// Do things for specific foo with traits B only
}
Foo DoMerge(Foo&, const Foo&, int, TraitsA)
{
// Do things for specific foo with TraitsA, or for any Foo
}
};
但是,这无法编译(至少在 ClientMergeFooTwo 中) > 的情况),说它无法转换 Foo&进入 SpecificFoo&。任何想法为什么它会失败,而不是在 MergeFoo
中选择完美的通用重载?
编辑:嗯,考虑到我尝试编写的速度,这个伪代码示例显然做得不太好。我已经纠正了一些错误...
I've got a program where I've got a lot of nested if/switch statements which were repeated in several places. I tried to extract that out and put the switches in a template method class, and then allow clients to overload which switch branches they wanted to specifically handle using overloading:
class TraitsA {};
class TraitsB : public TraitsA {};
class Foo
{
bool traitsB;
public:
// Whether or not a Foo has traitsB is determined at runtime. It is a
// function of the input to the program and therefore cannot be moved to
// compile time traits (like the Iterators do)
Foo() : traitsB(false) {}
virtual ~Foo() {}
bool HasTraitsB() const { return traitsB; }
void SetTraitsB() { traitsB = true; }
};
class SpecificFoo : public Foo
{
};
template <typename Client> //CRTP
class MergeFoo
{
protected:
Foo DoMerge(Foo&, const Foo&, int, TraitsA)
{
// Do things to merge generic Foo
}
public:
// Merge is a template method that puts all the nasty switch statements
// in one place.
// Specific mergers implement overloads of DoMerge to specify their
// behavior...
Foo Merge(Foo* lhs, const Foo* rhs, int operation)
{
const Client& thisChild = *static_cast<const Client*>(this);
SpecificFoo* lhsSpecific = dynamic_cast<SpecificFoo*>(lhs);
const SpecificFoo* rhsSpecific = dynamic_cast<const SpecificFoo*>(rhs);
// In the real code these if's are significantly worse
if (lhsSpecific && rhsSpecific)
{
if (lhs->HasTraitsB())
{
return thisChild.DoMerge(*lhsSpecific,
*rhsSpecific,
operation,
TraitsB());
}
else
{
return thisChild.DoMerge(*lhsSpecific,
*rhsSpecific,
operation,
TraitsA());
}
}
else
{
if (lhs->HasTraitsB())
{
return thisChild.DoMerge(*lhs, *rhs, operation, TraitsB());
}
else
{
return thisChild.DoMerge(*lhs, *rhs, operation, TraitsA());
}
}
}
};
class ClientMergeFoo : public MergeFoo<ClientMergeFoo>
{
friend class MergeFoo<ClientMergeFoo>;
Foo DoMerge(SpecificFoo&, const SpecificFoo&, int, TraitsA)
{
// Do things for specific foo with traits A or traits B
}
};
class ClientMergeFooTwo : public MergeFoo<ClientMergeFoo>
{
friend class MergeFoo<ClientMergeFooTwo>;
Foo DoMerge(SpecificFoo&, const SpecificFoo&, int, TraitsB)
{
// Do things for specific foo with traits B only
}
Foo DoMerge(Foo&, const Foo&, int, TraitsA)
{
// Do things for specific foo with TraitsA, or for any Foo
}
};
However, this fails to compile (At least in ClientMergeFooTwo
's case), saying it cannot convert a Foo& into a SpecificFoo&. Any ideas why it's failing that conversion instead of choosing the perfectly good generic overload in MergeFoo
?
EDIT: Well, this psuedocode example apparently didn't do so well given how fast I tried to write it. I have corrected some of the mistakes...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,因为名字隐藏规则。如果派生类中的函数与基类中的函数同名,则基类函数是“隐藏”的,它甚至不查看所涉及函数的参数。
也就是说,解决方案很简单:通过在公共部分中使用简单的
using MergeFoo::DoMerge
使基类版本在派生类中可用。Yes, because of name hiding rules. If a function in the derived class has the same name as a function in the base class, the base class function is "hidden", it doesn't even look at the parameters of the involved function.
That said, the solution is easy: Make the base class version available in the derived class with a simple
using MergeFoo::DoMerge
in the public part.我无法理解这一点? 类型(或变量)在哪里?您的意思是这样吗:
下面的
const 性不匹配,因为在目标中您忘记了 const。
I couldn't understand this? Where is the type (or the variable)? Did you mean this:
And in the following
there is mismatch in const-ness, as in the target you forgot
const
.可以使用更多关于它失败的地方的信息,但看起来为了做你想做的事情,你需要在公共 Merge 函数中调用 Client::DoMerge() 而不是仅仅调用 DoMerge() MergeFoo 的。
Could use a little more info on where it's failing, but it looks like in order to do what you mean to do, you need to be calling Client::DoMerge() instead of just calling DoMerge(), when in the public Merge function of MergeFoo.
这可能是问题的原因。
This could be the cause of the problem.