C ++ проверка типов во время компиляции - PullRequest
1 голос
/ 12 апреля 2010

все. Я довольно новичок в C ++ и пишу небольшую библиотеку (в основном для своих проектов) на C ++. В процессе проектирования иерархии типов я столкнулся с проблемой определения оператора присваивания.

Я использовал базовый подход, который в конечном итоге был достигнут в этой статье , а именно: для каждого класса MyClass в иерархии, производной от класса Base, вы определяете два оператора присваивания, как :

class MyClass: public Base {
public:
    MyClass& operator =(MyClass const& rhs);
    virtual MyClass& operator =(Base const& rhs);
};

// automatically gets defined, so we make it call the virtual function below
MyClass& MyClass::operator =(MyClass const& rhs);
{
    return (*this = static_cast<Base const&>(rhs));
}

MyClass& MyClass::operator =(Base const& rhs);
{
    assert(typeid(rhs) == typeid(*this)); // assigning to different types is a logical error
    MyClass const& casted_rhs = dynamic_cast<MyClass const&>(rhs);
    try {
        // allocate new variables
        Base::operator =(rhs);
    } catch(...) {
        // delete the allocated variables
        throw;
    }
    // assign to member variables
}

Меня интересует утверждение о равенстве типов. Поскольку я пишу библиотеку, в которой предположения, вероятно, будут скомпилированы из конечного результата, это привело меня к схеме, которая выглядит примерно так:

class MyClass: public Base {
public:
    operator =(MyClass const& rhs); // etc
    virtual inline MyClass& operator =(Base const& rhs)
    {
        assert(typeid(rhs) == typeid(*this));
        return this->set(static_cast<Base const&>(rhs));
    }
private:
    MyClass& set(Base const& rhs); // same basic thing
};

Но мне было интересно, смогу ли я проверить типы во время компиляции. Я посмотрел в Boost.TypeTraits и подошел ближе, выполнив BOOST_MPL_ASSERT((boost::is_same<BOOST_TYPEOF(*this), BOOST_TYPEOF(rhs)>));, но поскольку rhs объявлен как ссылка на родительский класс, а не на производный класс, он задохнулся.

Теперь, когда я думаю об этом, мои рассуждения кажутся глупыми - я надеялся, что, поскольку функция была встроенной, она сможет проверять сами параметры, но, конечно, препроцессор всегда запускается перед компилятором. Но мне было интересно, знает ли кто-нибудь о каком-либо другом способе проверки такого рода во время компиляции.

Ответы [ 2 ]

7 голосов
/ 12 апреля 2010

Вы не можете выполнить это утверждение во время компиляции по той простой причине, что типы времени выполнения не будут известны до, ну, во время выполнения.

assert(typeid(rhs) == typeid(*this));
return this->set(static_cast<Base const&>(rhs));

В не встроенной версии у вас было dynamic_cast. Я бы сохранил это, чтобы вы получили четко определенную ошибку, а не неопределенное поведение, если ваше утверждение нарушено.

Если вы сделаете это, утверждение будет чрезмерно ограничительным или бессмысленным. dynamic_cast вызовет исключение bad_cast в сборках отладки и выпуска. Это то, что вы хотите.

Лично я бы поставил под сомнение всю проблему полиморфного присваивания. Я бы следовал совету Скотта Мейерса «Эффективный C ++» и сделал бы все ваши неконечные узлы в иерархии наследования абстрактными. Затем вы можете сделать операторы назначения базового класса защищенными и не виртуальными.

Это позволяет использовать их реализацию в операторе присваивания производных классов, но не позволяет клиентам разрезать объекты. Если у клиентского класса есть только ссылка на базовый класс или указатель, то сомнительно, стоит ли пытаться присвоить классу так или иначе. Если это так, они должны нести ответственность за литье и гарантии безопасности типа.

0 голосов
/ 12 апреля 2010

Если вы хотите, чтобы вещи определялись во время компиляции, то динамический полиморфизм (виртуальные функции и т. Д.) Не подходит вам. Обычно я не вижу необходимости смешивать динамический полиморфизм с вещами, которые имеют «нормальные типы значений», например с операторами присваивания. Возможно, конкретные и неполиморфные классы - это то, что работает лучше всего в вашем случае. Но трудно сказать, потому что вы ничего не сказали о том, что вы пытаетесь делать с классами.

...