#include <iostream>
#include <type_traits>
#include <typeinfo>

template<typename Derived>
struct base
{
    void const_method() const
    {
        static_cast<Derived*>(this)->method();
    }
    
    void fixed_const_method() const
    {
        // base<derived> const*
        std::cout << typeid(this).name() << std::endl;
        // base<derived>
        std::cout << typeid(typename std::remove_pointer<decltype(this)>::type).name() << std::endl;
        // base<derived>
        std::cout << typeid(decltype(*this)).name() << std::endl;
        // derived const*
        std::cout << typeid(typename std::conditional<
                                std::is_const<
                                    typename std::remove_pointer<decltype(this)>::type>::value,
                                Derived const* const,
                                Derived* const>::type).name() << std::endl;
        
        static_cast<
            typename std::conditional<
                std::is_const<
                    typename std::remove_pointer<decltype(this)>::type>::value,
                Derived const* const,
                Derived* const>::type>(this)->method();
    }
};

struct derived : public base<derived>
{
    void method() const
    {
        std::cout << "const method" << std::endl;
    }

    void method()
    {
        std::cout << "non-const method" << std::endl;
    }
};

int main()
{
    derived d;
    d.fixed_const_method();
    
    return 0;
}