Сохраните постоянную или неконстантную ссылку в одном и том же шаблоне класса - PullRequest
2 голосов
/ 15 января 2020

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

Допустим, мы хотели бы иметь 1-элементный view массива.

Мой вопрос как заставить работать с объектами const и non-const.

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

#include <cassert>
#include <array>

template <typename T>
class View {
 private:
  const std::size_t index_;
  T &t_;
  using value_type = typename T::value_type;

 public:
  View(T &t, std::size_t index) : t_{t}, index_{index} {}

  const value_type &value() const { return t_[index_]; }
  value_type &value() { return t_[index_]; }
};

int main() {
  using Array = std::array<int, 2>;

  // The block below works
  {
    Array array{0, 0};
    View<Array> view(array, 0);
    view.value() = 5;
    assert(array[0] == 5);
  }

  // The block below gives a compilation error
  {
    const Array array{5, 5};
    View<Array> view(array, 0);
    assert(view.value() == 5);
  }
}

1 Ответ

5 голосов
/ 15 января 2020

Работает следующее:

#include <cassert>
#include <array>

template <typename T>
class View {
 private:
  using value_type = typename T::value_type;

  T &t_;
  const std::size_t index_;

 public:
  View(T &t, std::size_t index) : t_{t}, index_{index} {}

  const value_type &value() const { return t_[index_]; }

  template<class Arr = T, class = typename std::enable_if<!std::is_const<Arr>::value>::type>
  value_type &value() { return t_[index_]; }
};

int main() {
  using Array = std::array<int, 2>;

  // The block below works
  {
    Array array{0, 0};
    View<Array> view(array, 0);
    view.value() = 5;
    assert(array[0] == 5);
  }

  // The block below gives a compilation error
  {
    const Array array{5, 5};
    View<const Array> view(array, 0);
    assert(view.value() == 5);
  }
}

Если вы задаете View a const Array, вы также должны указать const Array в качестве аргумента шаблона.

Но затем вернуть не const ссылка с value() больше не работает, поэтому мы отключаем эту функцию с SFINAE, если тип массива const.

PS: у вас не будет последней проблемы, если ваш класс с именем View действительно был тем, чего можно было ожидать в представлении, то есть немодифицированным и даже не имел метода, возвращающего не const ссылку.

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