【问题标题】:What is the cause of this overload resolution headache?这种过载解决头痛的原因是什么?
【发布时间】: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


【解决方案1】:

任何想法为什么它会失败,而不是在 MergeFoo 中选择完美的通用重载?

是的,因为名称隐藏规则。如果派生类中的函数与基类中的函数同名,则基类函数是“隐藏”的,它甚至不看涉及到的函数的参数。

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

【讨论】:

    【解决方案2】:
    const thisChild& = *static_cast<const Client*>(this);
    

    我无法理解? 类型(或变量)在哪里?你是这个意思吗:

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

    在下面

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

    常量不匹配,如您忘记的目标const

    【讨论】:

    • 您在所有方面都是正确的。我对真实代码的拙劣拼凑模仿太快了:(
    【解决方案3】:

    可以使用更多关于失败位置的信息,但看起来为了执行您想要做的事情,您需要调用 Client::DoMerge() 而不是仅仅调用 DoMerge(),在MergeFoo 的公共 Merge 函数。

    【讨论】:

    • 对 DoMerge 的调用之一失败。我不认为调用Client::DoMerge 是明确要求的,因为我已经将this 转换为Client 类型。
    • 你做了,但是你需要调用 thisChild.DoMerge() 来获得想要的效果。
    • :叹息:我对这段代码的想法的转录是可怕的。 :( 很抱歉造成混乱!
    【解决方案4】:
    class ClientMergeFooTwo : public MergeFoo<ClientMergeFoo>
    

    这可能是问题的原因。

    【讨论】:

      猜你喜欢
      • 2016-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 2012-01-05
      • 1970-01-01
      • 2012-07-08
      相关资源
      最近更新 更多