Как присвоить псевдоним типа «указателю на массив const int»?

#c #arrays #pointers #alias #typedef

#c #массивы #указатели #псевдоним #typedef

Вопрос:

Я выполняю упражнения по псевдониму типа (пример 3.44 C Primer 5th). Приведенный ниже код сделает:

  1. псевдоним типа указателя на массив const int и

  2. псевдоним типа ссылки на массив const int

Однако результат не соответствует ожидаемому (см. Комментарии). Почему?

 int main(){

  int ia[3] = {0, 1, 2};

  typedef const int (*cpa)[3];
  cpa g = 0;                    //(gdb) ptype g: type = int (*)[3]

  typedef const int (amp;cra)[3];
  cra h = ia;                   //(gdb) ptype h: type = int (amp;)[3]

  return 0;

}
  

Когда я удаляю массив, он работает так, как ожидалось. Смотрите приведенный ниже код:

 int main(){

  int i = 42;

  typedef const int* cp;
  cp e = amp;i;                    //(gdb) ptype e: type = const int *

  typedef const intamp; cr;
  cr f = i;                     //(gdb) ptype f: type = const int amp;

  return 0;
}
  

И последнее, как переписать определение псевдонима, если использовать ключевое слово «using»?

Комментарии:

1. Почему это не то, что вы ожидаете?

2. @Joseph Mansfield значение const отсутствует

3. Это правильно, и using делает это еще проще, потому что вам не нужно имя в середине беспорядка. Кстати, вы также можете проверить во время компиляции. const int arr[3]; static_assert(std::is_same<cpa, decltype(amp;arr)>::value, "");

4. @chris Но «const» отсутствует, если с array

5. @user3701346, если ты имеешь в виду static_assert , то это не функция и не макрос, а объявление ( static-assert-declaration ). Если вы имеете в виду decltype , это спецификатор. Если вы имеете в виду, std::is_same это признак типа (просто структура с value членом в основном).

Ответ №1:

Это просто выходные данные вашей версии gdb , в которой опущено const . const По-прежнему важно. Мы можем доказать это с помощью следующей программы, которая не будет компилироваться:

 int main(){
  const int ia[3] = {0, 1, 2};

  typedef int (*cpa)[3];
  cpa g = 0;

  typedef int (amp;cra)[3];
  cra h = ia;

  return 0;
}
  

Для меня с gdb 7.7 результат соответствует ожидаемому:

 (gdb) ptype g
type = const int (*)[3]
(gdb) ptype h
type = const int (amp;)[3]
  

Чтобы переписать эти typedef s с using :

 using cpa = const int (*)[3];
using cra = const int (amp;)[3];
  

Вы можете видеть, что за шаблоном просто using identifier = следует объявление с отсутствующим идентификатором.

Комментарии:

1. Джозеф, не мог бы ты поделиться, включал ли ты какие-либо опции «print pretty»?

2. @user3701346 Если это означает выполнение enable pretty-printer заранее, похоже, это не имеет никакого эффекта.

3. подождите. cpa это имя типа, как вы можете его напечатать? Я только сделал ptype g и ptype h , которые являются переменными.

4. @user3701346 Тот же результат.

5. @user3701346 Я предполагаю, что это была ошибка, которая была исправлена между версиями 7.4 и 7.7

Ответ №2:

Вы слишком доверяете gdb. По причинам, которые я не понимаю, ‘const’ опускается. Вам следует проверять постоянство типов другими способами. Один из способов — попытаться присвоить g[0]. Это выдаст ошибку, которая включает в себя сообщение, подобное этому:

 error: incompatible types in assignment of ‘int’ to ‘const int [3]’
  

Это сразу говорит вам о том, что вашей проблемы не существует.

Вы также можете использовать typeid, чтобы получить тип из компилятора и распечатать его. На VC это выполняет работу тривиально. С помощью gcc вам нужно изменить формат результатов, чтобы сделать их удобочитаемыми. Приведенный ниже код выводит тип g и g2, с константой и без нее.

 #include <stdio.h>
#include <typeinfo>

#ifdef __GNUG__
#define DEMANGLE
#endif

#ifdef DEMANGLE
#include <cxxabi.h>
#endif

template <typename T>
const char* TypeName(const Tamp; type)
{
#ifdef DEMANGLE
    int status = 0;
    // Convert the cryptic gcc name decorations to something
    // human readable.
    return abi::__cxa_demangle(typeid(type).name(), NULL, NULL, amp;status);
#else
    return typeid(type).name();
#endif
}

int main(){

  int ia[3] = {0, 1, 2};

  typedef const int (*cpa)[3];
  cpa g = 0;                    //(gdb) ptype g: type = int (*)[3]
  typedef int (*cpa2)[3];
  cpa2 g2 = 0;                    //(gdb) ptype g: type = int (*)[3]

  typedef const int (amp;cra)[3];
  cra h = ia;                   //(gdb) ptype h: type = int (amp;)[3]

  printf("Type of 'g' is '%s'n", TypeName(g));
  printf("Type of 'g2' is '%s'n", TypeName(g2));

  //g[0] = 2; This fails to compile, thus proving that cpa/g have the correct type.

  return 0;

}
  

Комментарии:

1. Спасибо за совет. Теперь у меня есть альтернативный способ проверки типа.