pw_containers: Add static_assert for Item type

Assert that the item type T is derived from IntrusiveList<T>::Item. The
assert must be in a function, since the class T is not fully defined
when IntrusiveList<T> is instantiated.

Change-Id: I802c6d2fe5872694098525933e522365c6ca86e1
diff --git a/pw_containers/public/pw_containers/intrusive_list.h b/pw_containers/public/pw_containers/intrusive_list.h
index cba6c8c..14be30f 100644
--- a/pw_containers/public/pw_containers/intrusive_list.h
+++ b/pw_containers/public/pw_containers/intrusive_list.h
@@ -64,18 +64,20 @@
   using const_iterator =
       intrusive_list_impl::Iterator<std::add_const_t<T>, const Item>;
 
-  constexpr IntrusiveList() = default;
+  constexpr IntrusiveList() { CheckItemType(); }
 
   // Constructs an IntrusiveList from an iterator over Items. The iterator may
   // dereference as either Item& (e.g. from std::array<Item>) or Item* (e.g.
   // from std::initializer_list<Item*>).
   template <typename Iterator>
-  IntrusiveList(Iterator first, Iterator last) : list_(first, last) {}
+  IntrusiveList(Iterator first, Iterator last) : list_(first, last) {
+    CheckItemType();
+  }
 
   // Constructs an IntrusiveList from a std::initializer_list of pointers to
   // items.
   IntrusiveList(std::initializer_list<Item*> items)
-      : list_(items.begin(), items.end()) {}
+      : IntrusiveList(items.begin(), items.end()) {}
 
   template <typename Iterator>
   void assign(Iterator first, Iterator last) {
@@ -144,6 +146,14 @@
   const_iterator cend() const noexcept { return end(); }
 
  private:
+  // Check that T is an Item in a function, since the class T will not be fully
+  // defined when the IntrusiveList<T> class is instantiated.
+  static constexpr void CheckItemType() {
+    static_assert(
+        std::is_base_of<Item, T>(),
+        "IntrusiveList items must be derived from IntrusiveList<T>::Item");
+  }
+
   intrusive_list_impl::List list_;
 };