У меня есть следующие три файла в моем коде (большая часть кода удалена. Это просто, чтобы изолировать проблему).
global.h:
//global.h
#ifndef GLOBAL_H
#define GLOBAL_H
extern const int ARRAYSIZEX;
extern const int ARRAYSIZEY;
extern const int ARRAYSIZEZ;
#endif //GLOBAL_H
global.cpp:
//global.cpp
#include "global.h"const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;
главный:
//main
#include "global.h"using namespace std;
someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];
int main(int argc, char **argv)
{
//...
}
Компиляция дает мне три ошибки при объявлении mySomeTypeArray.
ошибка: граница массива не является целочисленной константой перед токеном ‘]’
Я хочу сохранить мои определения глобальной переменной и размера массива в global.h / cpp для этого приложения, просто для организации, чтобы все мои параметры конфигурации были в одном месте. Как правильно добиться того, что я пытаюсь сделать?
Спасибо
Ваше объявление терпит неудачу, потому что размеры массива нужно оценивать во время компиляции, а ваша схема инкапсуляции фактически скрывает значения от компилятора. Это правда, потому что компиляторы работают с отдельными единицами перевода. Во время компиляции main.cpp ваш компилятор видит только extern const int ARRAYSIZEX
благодаря include
оператор, но не значение, которое видно в отдельном блоке перевода, поэтому он не может определить структуру памяти.
В то время как const
переменные могут использоваться в качестве размеров массива в некоторых контекстах, язык обеспечивает более подходящий constexpr
квалификатор, который поставляется с набором ограничений, которые обеспечивают его оценку во время компиляции и пригодность для размеров массива. Я рекомендую всегда использовать его, когда это уместно, потому что это укажет вам на ошибку в таких ситуациях, как эта. В этом случае вы получите ошибку компилятора, потому что extern constexpr
Объявление плохо сформировано, что намекает на правильное решение: хранить значения для констант времени компиляции непосредственно внутри файла заголовка.
global.h
constexpr int ARRAYSIZEX = ...;
constexpr int ARRAYSIZEY = ...;
constexpr int ARRAYSIZEZ = ...;
main.cpp
#include "global.h"someType mySomeTypeArray[ARRAYSIZEX][ARRAYSIZEY][ARRAYSIZEZ];
Проблема здесь extern int x
средства «x
определяется в другом файле, но не беспокойтесь о деталях, все, что вам нужно знать, это int
Msgstr «Это обычно достаточно хорошо, за исключением случаев, когда компилятор должен знать прямо здесь и тогда, что x
является.
Поскольку это определено в другом файле, оно не может. Этот файл должен быть скомпилирован до того, как он узнает, и результат этой компиляции, из-за того, как работает C ++, не может повлиять на компиляцию этого файла.
Вы должны будете объявить это как const int
в заголовке, если вы хотите поделиться этими значениями. extern int
не будет сокращать это.
Хотя это тривиальный пример, на самом деле нет причин спускаться extern
дорога вообще. Просто определите значения в заголовочном файле как обычные const int
,
Размер массива должен быть указан целочисленным константным выражением. const int
Объект может использоваться в выражении целочисленной константы тогда и только тогда, когда он объявлен с помощью инициализатора и этот инициализатор также является выражением целочисленной константы. Ваш ARRAYSIZE...
переменные не удовлетворяют этому требованию. В main
они объявлены без инициализатора. Вы не можете использовать ARRAYSIZE...
переменные как размеры массивов в main
,
Если у вас нет особого требования дать этим переменным внешнюю связь, просто объявите (и определите) их в заголовке как
const int ARRAYSIZEX = 5;
const int ARRAYSIZEY = 2;
const int ARRAYSIZEZ = 4;
Эти объекты будут иметь внутреннюю связь, которая отличается от того, что пытается сделать ваш оригинальный вариант.
Если действительно хотите дать им внешнюю связь, объявите их как inline extern const
в шапке
inline extern const int ARRAYSIZEX = 5;
inline extern const int ARRAYSIZEY = 2;
inline extern const int ARRAYSIZEZ = 4;
поскольку inline
само по себе мешает const
от навязывания внутренней связи, extern
совершенно необязательно в этих декларациях. И с тех пор inline const
комбинация может быть заменена на constexpr
(как отметил @MM в комментариях), вы можете добиться того же эффекта, просто
constexpr int ARRAYSIZEX = 5;
constexpr int ARRAYSIZEY = 2;
constexpr int ARRAYSIZEZ = 4;
Проблема здесь в том, что ARRAYSIZEX
, ARRAYSIZEY
а также ARRAYSIZEZ
не являются константами времени компиляции. Они являются константами — поэтому их значения нельзя изменить, но их значения не известны компилятору.
В C ++ процесс компиляции состоит из 3 основных этапов.
В C ++ ключевое слово extern
для компилятора означает, что переменная «где-то» определена. Компилятор не знает реальный адрес переменной, но помещает ключевое слово extern
Гарантируется, что переменная действительно существует, и компоновщик сможет найти свой адрес по имени при создании исполняемого файла.
Проблема здесь в том, что компилятор на шаге 2 хочет создать объектный файл, но он не знает, насколько большим будет массив, потому что он не знает значения этих констант. Да, компоновщик на шаге 3, наконец, найдет их при объединении всех объектных файлов, но это слишком поздно для компилятора. Так что это порождает эту ошибку.
Решение простое. Используйте уже упоминалось constexpr
ключевое слово и инициализировать все переменные с инициализаторами. Ключевое слово constexpr
отмечает константы времени компиляции — константы, которые должны быть инициализированы в инициализаторах и известны компилятору.