Search code examples
c++templatesstatic-assert

How to determine if a type is derived from a template class at compile time?


Say I have some template classes:

template<class T>
class Foo{}

template<class T>
class Bar{}

Now, I want to make sure (at compile-time) that the type used in Bar is derived from Foo. I already found this answer that shows how to do it at runtime, but I would like to check at compile-time, maybe using static_assert or something.
Is there a way to do this?


Solution

  • Now, I want to make sure (at compiletime) that the type used in Bar is derived from Foo.

    You can do something like this:

    #include<type_traits>
    #include<utility>
    
    template<class T>
    class Foo{};
    
    template<typename T>
    std::true_type test(const Foo<T> &);
    
    std::false_type test(...);
    
    template<class T>
    class Bar {
        static_assert(decltype(test(std::declval<T>()))::value, "!");
    };
    
    struct S: Foo<int> {};
    
    int main() {
        Bar<S> ok1;
        Bar<Foo<int>> ok2;
        // Bar<int> ko;
    }
    

    See it on wandbox.
    The basic idea is that you can bind a temporary of type T to const Foo<U> & if T is derived from a specialization of Foo, no matter what's U. Therefore you can declare (no definition required) a couple of functions like the ones in the example to test it, then use the declared return type in a static_assert or any other constant context.


    Edit

    As suggested by @Quentin in the comments, probably it's worth replacing the reference with a pointer to prevent false positives from conversion constructors and operators.