Search code examples
c++templatesshared-ptrsmart-pointersc++-concepts

How to check if a shared_ptr type is of <type> statically?


I want to create a template container-class that should store instances of ABC-derived classes. With a constraint that only ABC-derived classes can use this template.

The container should be a static member of the derived class.

This is what I have now, though this won't work since extendsABC is not expecting a shared_ptr:

#include <list>
#include <memory>
#include <type_traits>

class ABC {
  virtual void foo() = 0;
};

template <typename T>
concept extendsABC = std::is_base_of<ABC, T>::value;

template <extendsABC T>
struct extendsABCStore {
  std::list<T> m_data;
};

struct Derived;

struct Derived : public ABC {
  void foo() override{};
  static extendsABCStore<std::shared_ptr<Derived>> instances;
};

Build output:

<source>:22:10: error: constraints not satisfied for class template 'extendsABCStore' [with T = std::shared_ptr<Derived>]
  static extendsABCStore < std::shared_ptr < Derived >> instances;
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:13:12: note: because 'std::shared_ptr<Derived>' does not satisfy 'extendsABC'
template < extendsABC T >
           ^
<source>:11:24: note: because 'std::is_base_of<ABC, shared_ptr<Derived> >::value' evaluated to false
  concept extendsABC = std::is_base_of<ABC, T>::value;
                       ^
1 error generated.
Compiler returned: 1

Solution

  • You have a couple of problems. Within the definition of Derived, it is an incomplete type, so extendsABC<Derived> is false. You also have a pointer where you want to constrain on the pointed-to type.

    To fix the first, we can use a static member function rather than a static data member.

    struct Derived : public ABC {
      void foo() override{};
      static auto& instances() {
        static extendsABCStore<Derived> store;
        return store;
      }
    };
    

    To fix the second, put std::shared_ptr in the definition of extendsABCStore

    template <typename T>
    struct extendsABCStore {
      std::list<std::shared_ptr<T>> m_data;
    };
    
    

    Full example at godbolt.