Перейти к содержанию

Последнее обновление:2026-10-12

Структурированные привязки в C++17

Прежде чем говорить о структурированных привязках, вот несколько интервью-вопросов — проверьте, сможете ли вы на них ответить?

  • Как получить доступ к закрытым членам собственного класса с помощью структурированных привязок?

  • Как изменить члены собственного класса с помощью структурированных привязок?

Вряд ли многие смогут ответить на эти вопросы, и ни вопросов, ни ответов в интернете нет. Отталкиваясь от них, мы придём к теме этой статьи: как поддержать структурированные привязки для собственных типов и какие здесь есть подводные камни?

Примечание: для ленивых — ответы и код уже выложены в сообществе (知识星球).

Чтобы изложение было более плавным, начнём с примера.

1.Собственный тип

Пусть дан класс:

struct Foo {
  Foo(int64_t id, std::string data) : id_(id), data_(std::move(data)) {}
  void Print() { std::cout << "id = " << id_ << ", data = " << data_ << std::endl; }

 private:
  int64_t id_;
  std::string data_;
};

Нужно, чтобы следующий код заработал:

int main() {
  Foo f{12, "hello world"};
  const auto& [id, data] = f;
  std::cout << "id = " << id << ", data = " << data << std::endl;
  f.Print();
}

При прямой компиляции получим:

 cannot decompose inaccessible member 'Foo::id_' of 'const Foo'
   42 |   const auto& [id, data] = f;

Как же быть?

2.Поддержка структурированных привязок

Эту задачу решим в два шага:

1.Специализируем std::tuple_size и std::tuple_element

namespace std {
  template <>
  struct tuple_size<Foo> : std::integral_constant<std::size_t, 2> {};

  template <>
  struct tuple_element<0, Foo> {
    using type = int64_t;
  };

  template <>
  struct tuple_element<1, Foo> {
    using type = std::string;
  };
}

2.Добавим к приведённой выше структуре дружественные функции get и реализуем их:

template <std::size_t Index>
decltype(auto) get(const Foo& f);

template <>
decltype(auto) get<0>(const Foo& f) {
  return f.id_;
}

template <>
decltype(auto) get<1>(const Foo& f) {
  return f.data_;
}

Теперь всё работает корректно и мы получаем вывод:

id = 12, data = hello world
id = 12, data = hello world

Напоследок несколько вопросов:

  • Выше показан доступ только для чтения; что произойдёт, если при доступе попытаться модифицировать через const auto &?

Например:

auto& [id, data] = f;
  • Как поддержать доступ с изменением членов класса?

То есть, чтобы этот оператор мог нормально работать:

auto& [id, data] = f;

Ну вот и всё, на этом раздел закончен — обсуждайте в комментариях.

Похожие темы

Комментарии