【发布时间】:2011-06-30 23:09:19
【问题描述】:
我有一个程序,其中有很多嵌套的 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 中选择完美的通用重载?
编辑:好吧,考虑到我尝试编写它的速度,这个伪代码示例显然做得不太好。我已经纠正了一些错误...
【问题讨论】:
-
贴出错误,同时注明行号。
-
@Nawaz:我不能——这不是原始代码,我不能在这里发布原始代码。它无法编译对
DoMerge的调用,并且由于隐式转换而失败。 -
你的例子在你的盒子上真的失败了吗?我刚刚用VS2010测试了一下,没有报错。
标签: c++ templates traits crtp overload-resolution