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

template <class T> struct type_printer { static void print() { std::cout << typeid(T).name(); } };
template <class T> struct type_printer<T const> { static void print() { type_printer<T>::print(); std::cout << " const"; } };
template <class T> struct type_printer<T*> { static void print() { type_printer<T>::print(); std::cout << " *"; } };
template <class T> struct type_printer<T&> { static void print() { type_printer<T>::print(); std::cout << " &"; } };

#define printtype(...) type_printer<__VA_ARGS__>::print()
#define printtype_line(...) do { std::cout << #__VA_ARGS__ ": " << std::endl; printtype(__VA_ARGS__); std::cout << std::endl; } while (0)

template<typename Derived>
struct base
{
    void const_method() const
    {
        static_cast<Derived*>(this)->method();
    }
    
    void fixed_const_method() const
    {
        // base<derived> const*
        printtype_line(decltype(this));
        // base<derived>
        printtype_line(typename std::remove_pointer<decltype(this)>::type);
        // base<derived>
        printtype_line(decltype(*this));
        // derived const*
        printtype_line(typename std::conditional<
                                std::is_const<
                                    typename std::remove_pointer<decltype(this)>::type>::value,
                                Derived const* const,
                                Derived* const>::type);
        
        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;
}