コンテンツにスキップ

最終更新:2026-10-12

C++17 構造化束縛

構造化束縛の話の前に、面接問題がいくつかあります。あなたは解けますか?

  • 構造化束縛を使って自作クラスのprivateメンバにアクセスするにはどうしますか?

  • 構造化束縛を使って自作クラスのメンバを変更するにはどうしますか?

これらの問題に答えられる人はおそらくほとんどいないでしょうし、問題と答えはネット上にもありません。これらの問題を出発点として、本記事の内容を引き出します。すなわち、自作型で構造化束縛をサポートする方法と、そこにはどんな落とし穴があるかです。

注:お手軽版として、答えとコードは星球に置いてあります。

本記事の内容をよりスムーズにするため、例から始めます。

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.構造化束縛をサポートする

この問題は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.上の構造体にfriendな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;

それでは、本節はここまでです。コメント欄で交流しましょう。

関連トピック

コメント