Дизайн: взаимозависимость константных и неконстантных аксессоров?

Возможный дубликат:
Как удалить дублирование кода между похожими константными и неконстантными функциями-членами?

В следующем примере:

template<typename Type, unsigned int Size>
class MyClass
{
public: inline Type& operator[](const unsigned int i)
{return _data[i];}

public: inline const Type& operator[](const unsigned int i) const
{return _data[i];}

protected: Type _data[Size];
};

постоянный и неконстантный operator[] реализуются независимо.

С точки зрения дизайна лучше иметь:

  • 1) две независимые реализации, как здесь
  • 2) одна из двух функций вызывает другую

Если решение 2) лучше, каким был бы код данного примера?

0

Решение

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

const метод не может вызвать не-const один.

Затем на-const метод не может вызвать const один, потому что нужно будет привести тип возвращаемого значения.

1

Другие решения

Это хорошо известный и широко принятый шаблон реализации, когда неконстантный метод реализуется через его константный аналог, как в

 class some_class {

const some_type& some_method(arg) const
{
...;
return something;
}

some_type& some_method(arg)
{
return const_cast<some_type&>(
const_cast<const some_class *>(this)->some_method(arg));
}
};

Это совершенно приемлемый метод, который по существу не имеет сопоставимых (в удобстве) альтернатив в ситуациях, когда тело метода является относительно тяжелым. Зло const_cast значительно меньше, чем зло дублированного кода.

Однако, когда тело метода по существу является однострочным, может быть лучше придерживаться явно идентичной реализации, просто чтобы избежать этого едва читаемого набора const_casts.

Вероятно, можно придумать формально лучше разработанное решение без кастинга, реализованное по принципу

 class some_class {

template <typename R, typename C>
static R& some_method(C *self, arg)
{
// Implement it here in terms of `self->...` and `R` result type
}

const some_type& some_method(arg) const
{
return some_method<const some_type>(this, arg);
}

some_type& some_method(arg)
{
return some_method<some_type>(this, arg);
}
};

но для меня это выглядит даже менее элегантно, чем подход с const_cast,

4

К сожалению, шаблоны «constness» не работают, но я все же думаю, что стоит рассмотреть общую идею:

// NOTE: this DOES NOT (yet?) work!
template <const CV>
Type CV& operator[](unsigned int index) CV {
...
}

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

0
По вопросам рекламы [email protected]