Как реализовать нечто вроде reinterpret_cast, но без необходимости указывать все спецификаторы?

Рейтинг: 1Ответов: 1Опубликовано: 16.08.2023

Устал постоянно писать reinterpret_cast с указанием всех спецификаторов (const, volatile). Придумал шаблон.

template<typename toT, typename T>
static inline auto toType(T val) {
  using t2 = typename cond< 
    is_const<T>,
    typename cond <
      log_and< is_pointer<T>, is_pointer<toT> >,
      const typename remove_pointer<toT>::type *,
      toT 
      >::type,
    toT
  >::type;
  return reinterpret_cast< t2 >(val);
}

Как видите, получилось нечто монструозное, и это только с учётом спецификатора const. Код не по стандарту, так как всё самописное, но суть не меняет. Код работает.

Можно ли более простым способом менять интерпретацию данных? Суть такая: допустим есть переменная типа const volatile char * A, нужно изменить доступ с побайтового до, допустим целочисленного, то есть const volatile int * A. Простой reinterpret_cast<int*>(A) отбросит и const и volatile.

Решение на основании ответа:

template<typename TValue>
struct remove_pointer<TValue *> {
  using type = TValue;
};

template<typename T>
auto toType(void* p) {
  return reinterpret_cast< typename remove_pointer<T>::type *>(p);
}

template<typename T>
auto toType(const void* p) {
  return reinterpret_cast<const typename remove_pointer<T>::type*>(p);
}

template<typename T>
auto toType(volatile void* p) {
  return reinterpret_cast<volatile typename remove_pointer<T>::type*>(p);
}

template<typename T>
auto toType(const volatile void* p) {
  return reinterpret_cast<const volatile typename remove_pointer<T>::type*>(p);
}

Ответы

▲ 1Принят

Четыре перегрузки самостоятельно разберутся с const и volatile квалификаторами:

#include <iostream>

template<typename T>
T *cast(void *p) {
    return reinterpret_cast<T *>(p);
}

template<typename T>
const T *cast(const void *p) {
    return reinterpret_cast<const T *>(p);
}

template<typename T>
volatile T *cast(volatile void *p) {
    return reinterpret_cast<volatile T *>(p);
}

template<typename T>
const volatile T *cast(const volatile void *p) {
    return reinterpret_cast<const volatile T *>(p);
}

int main() {
    int i = 0;
    void *p = &i;
    const void *cp = &i;
    volatile void *vp = &i;
    const volatile void *cvp = &i;
    
    std::cout << typeid(cast<int>(p)).name() << '\n';
    std::cout << typeid(cast<int>(cp)).name() << '\n';
    std::cout << typeid(cast<int>(vp)).name() << '\n';
    std::cout << typeid(cast<int>(cvp)).name() << '\n';
}
$ g++ cast.cpp 

$ ./a.out 
Pi
PKi
PVi
PVKi

P.S. Пример приведён для (const) (volatile) void *, но точно также можно работать с (const) (volatile) unsigned char *