Какова причина этой головной боли разрешения перегрузки? - PullRequest
0 голосов
/ 01 июля 2011

У меня есть программа, в которой есть много вложенных операторов 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 : Ну, этот пример psuedocode, видимо, не очень хорошо, учитывая, как быстро я пытался написать его. Я исправил некоторые ошибки ...

Ответы [ 4 ]

2 голосов
/ 01 июля 2011

Есть идеи, почему не удается выполнить это преобразование, вместо того, чтобы выбрать отличную универсальную перегрузку в MergeFoo?

Да, из-за правил сокрытия имен. Если функция в производном классе имеет то же имя, что и функция в базовом классе, функция базового класса «скрыта», она даже не смотрит на параметры задействованной функции.

Тем не менее, решение простое: сделать версию базового класса доступной в производном классе с простой using MergeFoo::DoMerge в публичной части.

0 голосов
/ 01 июля 2011
class ClientMergeFooTwo : public MergeFoo<ClientMergeFoo>

Это может быть причиной проблемы.

0 голосов
/ 01 июля 2011

Можно использовать немного больше информации о том, где происходит сбой, но, похоже, чтобы сделать то, что вы хотите сделать, вам нужно вызывать Client :: DoMerge () вместо того, чтобы просто вызывать DoMerge (), когда в публичная функция слияния MergeFoo.

0 голосов
/ 01 июля 2011
const thisChild& = *static_cast<const Client*>(this);

Я не мог этого понять? Где тип (или переменная )? Вы имели в виду это:

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

и далее

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

есть несоответствие в константности, так как в цели вы забыли const.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...