С++ лучший способ определить константы между файлами

Я работаю над игрой и у меня есть интересный вопрос. У меня есть некоторые постоянные значения для всей игры, которые я хочу реализовать в одном файле. Прямо сейчас у меня есть что-то вроде этого:

константы.cpp

extern const int BEGINNING_HEALTH = 10;
extern const int BEGINNING_MANA = 5;

константы.hpp

extern const int BEGINNING_HEALTH;
extern const int BEGINNING_MANA;

А затем файлы просто #include "constants.hpp". Это прекрасно работало, пока мне не понадобилось использовать одну из констант в качестве параметра шаблона, потому что константы, связанные извне, не являются допустимыми параметрами шаблона. Итак, мой вопрос: как лучше всего реализовать эти константы? Я боюсь, что простое помещение констант в заголовочный файл приведет к тому, что они будут определены в каждой единице перевода. И я не хочу использовать макросы.

Спасибо


person rlbond    schedule 13.03.2009    source источник


Ответы (8)


Избавьтесь от extern, и все готово.

Этот код отлично работает в заголовке, потому что все «действительно постоянно» и, следовательно, имеет внутреннюю связь:

const int BEGINNING_HEALTH = 10;
const int BEGINNING_MANA = 5;
const char BEGINNING_NAME[] = "Fred";
const char *const BEGINNING_NAME2 = "Barney";

Этот код нельзя безопасно поместить в заголовочный файл, потому что каждая строка имеет внешнюю связь (либо явно, либо из-за того, что она не является действительно постоянной):

extern const int BEGINNING_HEALTH = 10;
extern const int BEGINNING_MANA = 5;
const char *BEGINNING_NAME = "Wilma";  // the characters are const, but the pointer isn't
person Tom    schedule 13.03.2009
comment
я подозреваю ошибку копирования/вставки в последнем BEGINNING_NAME[]. вы хотели написать как BEGINNING_NAME ? - person Johannes Schaub - litb; 13.03.2009
comment
Вам нужен static, иначе вы не получите внутреннюю связь или, что более идеально, эквивалент #define со встроенными значениями. - person Jim Buck; 18.03.2009
comment
Константы @Jim Buck в C++ имеют внутреннюю связь - нет необходимости в статике - person ; 23.01.2010

Как насчет перечислений?

константы.hpp

  enum {
    BEGINNING_HEALTH = 10,
    BEGINNING_MANA = 5
  }
person Tommy Hui    schedule 13.03.2009

Используйте «static const int» в вашем файле .hpp и ничего не добавляйте в файл .cpp (кроме любого другого кода, который у вас есть, конечно).

person Jim Buck    schedule 13.03.2009

использовать пространства имен:

namespace GameBeginning {
    const int HEALTH = 10;
    const int MANA   = 5; 
};

тогда вы можете использовать как player.health = GameBeginning::HEALTH;

person user77682    schedule 13.03.2009

Большинство компиляторов просто не выделяют место для значений const POD. Они оптимизируют их и обращаются с ними так, как если бы они были #defined, не так ли?

person greyfade    schedule 13.03.2009
comment
Близко, но все же не совсем то. Пример, когда макросы работают, а константы нет: #define FOO foo; \ const char *str = bar FOO; C и C++ допускают конкатенацию токенов строковых литералов, но не строковых констант. - person Tom; 13.03.2009
comment
Это справедливо только для интегральных констант. Плавающие, двойные, char * и другие типы будут выделены для хранения, если оптимизация отключена. - person Adam Rosenfield; 13.03.2009
comment
@ Том: Я не это имел в виду. Я имел в виду константы POD, а не махинации препроцессора. Я имел в виду, что символ и место для значения не существуют, если вы не попытаетесь получить его адрес. - person greyfade; 13.03.2009
comment
Я думаю, что POD официально включает числа с плавающей запятой и двойные числа, но обычно числа с плавающей запятой и двойные числа не оптимизируются таким образом. - person Max Lybbert; 13.03.2009

Что случилось с простым:

#define BEGINNING_HEALTH 10

Чувак, это были дни.
Ой, подождите, эти до сих пор дни!

person slacy    schedule 13.03.2009
comment
Это может не сработать в контексте параметров шаблона... :) Это нужно rlbond. - person Mihai Limbășan; 13.03.2009
comment
Некоторым из нас нравится, когда наши отладчики показывают «BEGINNING_HEALTH» вместо «10». - person JoeG; 13.03.2009
comment
‹sarcastic› Когда нужны отладчики, когда у вас есть printf()? ‹/саркастический› - person slacy; 13.03.2009
comment
printf, #define, что дальше. Это С++. - person Sebastian Mach; 29.09.2011

возможно, что-то вроде статического класса?

class CONSTANTS {
public:
static inline int getMana() { return 10;};
};
person MighMoS    schedule 13.03.2009
comment
Это не помогает. Значения функций нельзя использовать в качестве параметров шаблона. Ключевое слово С++ 0x constexpr должно обойти это. Кроме того, в C++ есть пространства имен, которые лучше статического класса для констант пространства имен. - person Tom; 13.03.2009

В качестве быстрого ответа на вопрос, заданный в заголовке, можно сказать, что шаблон singleton — это, возможно, наилучший способ C++ для определения межфайловых констант и обеспечения только одного экземпляра объекта.

Что касается проблемы с параметром шаблона, вам нужно передать тип, а не значение. Ваш тип "int".

person jeffD    schedule 13.03.2009
comment
Это кажется излишним для набора простых констант и вряд ли решит его проблемы с созданием экземпляров шаблона. - person Eclipse; 13.03.2009
comment
Почему бы не решить его проблему с созданием экземпляра шаблона, ведь это будет не внешний, а локальный. Overkill относителен, какова перспектива качества в 100 миллионов долларов, 100 тысяч долларов или 100 долларов игрового бюджета? - person jeffD; 13.03.2009
comment
jeffD, проблема в том, что твой ответ не имеет смысла. вы хотите сделать int синглтоном? int состоит из значения, а не из идентификатора. еще одна вещь, которая, вероятно, заставила людей отказаться от вас, заключается в том, что он не хочет передавать тип, а значение в свой шаблон. Почему ты говоришь, что он не может? - person Johannes Schaub - litb; 13.03.2009
comment
Название вопроса само по себе хороший вопрос. Может быть, мне действительно нужно увидеть больше его кода. Ссылку см. на cplusplus.com/doc/tutorial/templates.html. Параметр шаблона — это особый тип параметра, который можно использовать для передачи типа в качестве аргумента. Пожелание комментарии разрешены гиперссылки. - person jeffD; 13.03.2009
comment
Хорошо, http-адрес автоматически становится гиперактивным. - person jeffD; 13.03.2009
comment
jeffD, к сожалению, туториал на cplusplus.com не совсем хорош - слишком неполный, а иногда и неправильный. например, объявления шаблонов не являются выражениями, как говорится, это объявления. также стирает разницу между специализацией и явной специализацией на своей странице. - person Johannes Schaub - litb; 13.03.2009
comment
лучше получить хорошую книгу (в SO есть несколько хороших тем о книгах по C++), а не полагаться на cplusplus.com . даже для справки, в нем есть несколько явно неправильных страниц (интересно, они все еще поддерживают их?). и, пожалуйста, прочитайте самый конец на этой связанной странице (о нетиповых параметрах). - person Johannes Schaub - litb; 13.03.2009
comment
Для справки, вы можете передавать целочисленные значения в шаблоны (я полагаю, Boost.Array использует эту возможность). - person Max Lybbert; 13.03.2009
comment
jeffD, у меня есть класс Matrix, который использует статический массив. Его подписью класса является шаблон ‹typename T, int Rows, int Columns› class Matrix. Это совершенно законный код C++. - person rlbond; 13.03.2009
comment
Я настаиваю на своем ответе на заглавный вопрос. Возможно, вы правы в том, что он делает с шаблонами, не видя кода и ошибки, это неуверенно. Здесь действительно два вопроса, я думаю, что я задам один как отдельный вопрос. - person jeffD; 13.03.2009