Search code examples
c++templatestemplate-specializationderived-class

derived class as a parameter of templated function which is specialized for its base class


class Base {};

class Derived : public Base {};

class SomeClass
{
    template<typename T>
    static void SetContent(T* pChild, OVariant content)
    {
        LOG_ASSERT(0, "All classes must be specialized!.  Please provide implementation for this class.");
    }
};

template <>
void SomeClass::SetContent(Base* value) 
{
    LOG_TRACE("Yay!");
}

int main() {
    SomeClass foo;
    Derived derived;
    foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value) 
    
    return 0;
}

When I call foo.SetContent(derived), I get the Assert. Is it not possible for the derived class to use the specialization for it's base class?


Solution

  • You can convert a Derived* to a Base*, but I think you rather want to specialize for all T that have Base as base

    #include <type_traits>
    #include <iostream>
    class Base {};
    
    class Derived : public Base {};
    
    
    template <typename T,typename = void>
    struct impl {
        void operator()(T*) {
            std::cout <<"All classes must be specialized!.  Please provide implementation for this class.\n";
        }
    };
    template <typename T>
    struct impl<T,std::enable_if_t<std::is_base_of_v<Base,T>>> {
        void operator()(T*) {
            std::cout << "Yay\n";
        }
    };
    
    class SomeClass
    {
        public:
        template<typename T>
        static void SetContent(T* pChild)
        {
            impl<T>{}(pChild);    
        }
    };
    
    struct bar{};
    
    int main() {
        SomeClass foo;
        Derived derived;
        foo.SetContent(&derived);
        bar b;
        foo.SetContent(&b);
    }
    

    Output:

    Yay
    All classes must be specialized!.  Please provide implementation for this class.
    

    //want it to call SomeClass::SetContent(Base* value)

    Note that if the template argument is deduced, it will be deduced as Derived not as Base and the argument is Derived*. SomeClass::SetContent<Base>(&derived); would already work as expected with your code (because Derived* can be converted to Base*).