6

It appears that std::remove_const isn't able to remove the const-ness of const char*. Consider the following code:

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

template< typename T >
struct S
{
    static void foo( ) {
        std::cout << typeid(T).name() << std::endl;
        std::cout << typeid( std::remove_const<T>::type ).name() << std::endl;
    }
};


int main( )
{
    S<char const*>::foo();
}

Output of this program (on Visual Studio 2010):

char const *
char const *

And in gcc we have the readable output (code here):

PKc
PKc

I would hope to get char * on the second line of Microsoft compiler, and whatever (but different than 1st line) on gcc. What am I doing wrong? How do I turn char const* to char*?

Uri London
  • 10,631
  • 5
  • 51
  • 81
  • 5
    `char const*` is a pointer to const, it's not const itself. – Pubby Nov 20 '12 at 18:13
  • The code you've posted won't even compile on gcc without `typename std::remove_const ...` – Praetorian Nov 20 '12 at 18:15
  • Yes, I had to add typename for the gcc compiler. The code for gcc is here: http://ideone.com/Vd25T8 – Uri London Nov 20 '12 at 18:19
  • 2
    @Uri You should always have the `typename`, not just add it for gcc. `std::remove_const::type` is a dependent type (since it depends on `T`) and the standard requires that it be preceded by the `typename` keyword to indicate that. MSVC will compile the code both with and without the `typename`, but it really should not be accepting the code if you omit it. [Here's](http://stackoverflow.com/questions/6273176/what-exactly-is-broken-with-microsoft-visual-cs-two-phase-template-instanti) an explanation of why this is broken in MSVC. – Praetorian Nov 20 '12 at 18:24

2 Answers2

9

char const* is a pointer to a const char, but the pointer itself is not const. To remove the constness from the type being pointed to, you could do this:

std::add_pointer<typename std::remove_const<typename std::remove_pointer<T>::type>::type>::type

Or alternatively:

typename std::remove_const<typename std::remove_pointer<T>::type>::type*

We remove the pointer from const char* to get const char, then remove const to get char, then add the pointer back to get char*. Not particularly pretty. To test:

typedef const char * type_before;
std::cout << typeid(type_before).name() << std::endl;
typedef typename std::remove_const<typename std::remove_pointer<type_before>::type>::type* type_after;
std::cout << typeid(type_after).name() << std::endl;

With g++ on my system, this outputs:

PKc
Pc

This should give you a hint about what "PKc" means. P for pointer, c for char, and K for konst ;)

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
9

If you want to remove all const qualifiers you need a solution that recursively removes const from all levels:

template<typename T> struct remove_all_const : std::remove_const<T> {};

template<typename T> struct remove_all_const<T*> {
    typedef typename remove_all_const<T>::type *type;
};

template<typename T> struct remove_all_const<T * const> {
    typedef typename remove_all_const<T>::type *type;
};

int main() {
    std::cout << typeid(remove_all_const<int const * * const>::type).name() << '\n';
}
bames53
  • 86,085
  • 15
  • 179
  • 244