C++ traits vs. if constexpr

Long time ago I wrote about C++ traits and how to use them to write functions which can have different bodies depends on the template type they use.

The example I was using was a simple container of an unspecified type which deletes its content if the type was a pointer. It was something like this:
template<typename T>
class myContainer
{
public:
    T myElement;
    
    // This function will be compiled only when T is a pointer
    template <typename T>
    inline typename std::enable_if<std::is_pointer<T>::value, void>::type DestroyElement()
    {
        delete myElement;
    }
    
    // This function will be compiled only when T is not a pointer
    template <typename T>
    inline typename std::enable_if<!std::is_pointer<T>::value, void>::type DestroyElement()
    {}

    ~myContainer()
    {
        DestroyItem<T>();
    }
}
This solution works but it's not elegant. It requires two complicated function templates to write.
A better solution would be to simply put such a code into a destructor:
if (std::is_pointer<T>::value)
{
    delete myElement;
}
But the compiler will fail to compile a delete myElement part when myCointainer class will use non pointer type.
Luckily with C++17 we've got a solution:
if constexpr (std::is_pointer<T>::value)
{
    delete myElement;
}
if constexpr is a statement that tells compiler to compile the following scope of code only when the expression it evaluates is true. Because this evaluation happens during compile time the expression must always be a constexpr. Fortunate for us - traits are!

From now on, if you want to implement a functionality that can work only on a specific types of data, you can use if constexpr and traits to your advantage!