1

I have the following typedef defined in a certain file:

typedef const uint8_t* BufType;

and in another file, I need to remove the constantness of the pointer. I cannot use the old c-style cast: (uint8_t*). How can this be achieved?

Exact Scenario: I have template specialization to deduce data type:

template<Enum E>
struct deduce_datatype_from {};

// Specialization
template<>
struct deduce_datatype_from<E1> {
  typedef BufType const uint8_t*;
}

I use this in a function template which is defined as follows:

template <Enum E>
void f(deduce_datatype_from<E>::BufType buf);

// function specialization.
template <>
void f<E1>(deduce_datatype_from<E1>::BufType buf) {
  struct write_struct write_req; 
  write_req.buf = (??)buf; 
}

In this case, write_struct is provided by a lib but no modification happens to buf, so it should be safe.

Aman Deep Gautam
  • 8,091
  • 21
  • 74
  • 130
  • 1
    Note that if you cast const away from an object that was declared const, and then write to the object, your program will have Undefined Behaviour and be an invalid program and the compiler is *not* required to warn you about it, but may silently generate broken code. – Jesper Juhl Jan 05 '20 at 18:13
  • Wouldn't it be easier if your `deduce_datatype_from` would just not return that `const`? Adding a const is very simple, after all. – Nico Schertler Jan 05 '20 at 18:24
  • You could use `std::remove_pointer`, then `std::remove_const` and finally, `std::add_pointer`? This will give you the pointer without the `const`. Alternatively, can you dereference the pointer before assignment and use the address? – Constantinos Glynos Jan 05 '20 at 18:46

1 Answers1

1

You can define a template function that is overloaded for pointers:

template <typename T>
T& remove_const(const T& value)
{
    return const_cast<T&>(value);
}

template <typename T>
T* remove_const(const T* value)
{
    return const_cast<T*>(value);
}

And call it as so:

std::array<const uint8_t, 8> buf = {'\0'};

BufType cdata = buf.data();
uint8_t* data = remove_const(data);

If you want a way to express the resulting type, i.e. remove the const of the pointed-to type, you could define a type trait like this (or define template specializations, as in the function case):

template <typename T>
struct remove_pointed_to_const
{
    using type = std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>;
};

// This static_assert is correct.
static_assert(std::is_same<remove_pointed_to_const<BufType>::type, uint8_t*>::value);

In this alternative, you could use const_cast directly at the point of use, which might make it easier to identify all const_cast locations in a project:

std::array<const uint8_t, 8> buf = {'\0'};  
BufType const cdata = buf.data();
uint8_t* data = const_cast<remove_pointed_to_const<BufType>::type>(data);

As a comment said, and as with all const_cast usages, you need to be careful not to apply this to an object that was initialized as a const object. Doing so would be UB.

NicholasM
  • 4,557
  • 1
  • 20
  • 47