这种超负荷解决头痛的原因是什么

What is the cause of this overload resolution headache?

本文关键字:是什么 超负荷 解决      更新时间:2023-10-16

我有一个程序,其中有很多嵌套的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中选择完全好的泛型重载,而是失败了转换?

EDIT:好吧,考虑到我写的速度,这个伪代码示例显然做得不太好。我已经纠正了一些错误。。。

有什么想法吗?为什么它没有在MergeFoo中选择非常好的泛型重载,而是失败了转换?

是的,因为名字隐藏规则。如果派生类中的函数与基类中的函数同名,则基类函数是"隐藏的",它甚至不查看相关函数的参数。

也就是说,解决方案很简单:在公共部分使用简单的using MergeFoo::DoMerge,使基类版本在派生类中可用。

const thisChild& = *static_cast<const Client*>(this);

我听不懂?类型(或变量(在哪里?你的意思是:

const Client & thisChild = *static_cast<const Client*>(this);

在下面的中

SpecificFoo* rhsSpecific = dynamic_cast<const SpecificFoo*>(rhs);

常量不匹配,就像您忘记了const的目标一样。

可以使用更多关于它在哪里失败的信息,但看起来为了完成你想要做的事情,你需要在MergeFoo的公共Merge函数中调用Client::DoMerge((,而不仅仅是调用DoMerge(。

class ClientMergeFooTwo : public MergeFoo<ClientMergeFoo>

这可能是问题的原因。