До недавних пор всё время придерживался политики "любой литерал в коде должен быть представлен в виде соответствующего макроса, добавленного в предкомпиляционный заголовочный файл или в какой-нибудь common.h". Делал я так даже в том случае, если контекст использования данной константы (по крайней мере, на текущий момент) сильно ограничен (например, она используется лишь внутри одной функции / класса / etc). С недавних пор решил поступать иначе — заводить константные объекты внутри этих самых модулей:
class Foo
{
public:
Foo() : SOME_CONSTANT_VALUE(0) {}
private:
const int SOME_CONSTANT_VALUE;
};
Такой вариант мне тоже не очень нравится. Например, в классах, при наличии довольно большого кол-ва констант, будет(ут) довольно некрасивый(ые) конструктор(ы):
Да, с delegating costructors из C++11 такое можно написать всего лишь в одном конструкторе, но особо положения дел это не меняет, на мой взгляд.
Более того, когда все константы вынесены в отдельный заголовочный файл, их проще находить и редактировать. При чтении же конкретного модуля, я думаю, не составит труда перейти на определение символа под курсором.
Да и смотрится это как-то, честно говоря, странно — вроде и член класса, но при этом константа. Не называть же объект как-нибудь _SOME_CONSTANT_VALUE, чтобы подчеркнуть и то, и другое?
FH>Такой вариант мне тоже не очень нравится.
Ну так действительно делать не имеет большого смысла. Ведь если член имеет одно и то же значение для всех экземпляров класса, то незачем его хранить в каждом из них:
class Foo {
static const int SOME_CONSTANT_VALUE = 0;
};
И на конструкторы это никак теперь не влияет.
FH>Более того, когда все константы вынесены в отдельный заголовочный файл, их проще находить и редактировать. При чтении же конкретного модуля, я думаю, не составит труда перейти на определение символа под курсором.
Ну есть константы на века, а есть константные параметры, через которые настраивается поведение программы, и которые-таки иногда меняются. Вполне допустимо, что первые определены максимально близко к месту использования, а вторые собраны где-то в отдельном файле в библиотеке. И так, и так приходится делать.
Здравствуйте, FrozenHeart, Вы писали:
FH>Как Вы поступаете в подобных случаях?
Зависит от логики. Иногда const, иногда enum, иногда лучше прямо в коде литерал (есть случаи когда литерал более понятен читающему, чем длинное_мнемоническое_имя_важной_константы).
Правило всегда одно, компилятору пофиг, а программу будут читать люди и она им должна быть понятна.
Здравствуйте, niXman, Вы писали:
X>но для целочисленных все же предпочитаю enum.
enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
Здравствуйте, VladFein, Вы писали:
X>>но для целочисленных все же предпочитаю enum.
VF>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
Здравствуйте, VladFein, Вы писали:
VF>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
как скажешь. даже спорить с тобой не стану.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, VladFein, Вы писали:
X>>>но для целочисленных все же предпочитаю enum.
VF>>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
NB>static const double?
Здравствуйте, niXman, Вы писали:
VF>>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления. X>как скажешь.
Я именно так и сказал.
X>даже спорить с тобой не стану.
А что так? Не уважаешь???
Здравствуйте, VladFein, Вы писали:
VF>enum { f = 3.14; } ???
1. и какой компилятор такое компилирует?
2. точку с запятой не там поставил.
3. не ведаешь что творишь.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Здравствуйте, VladFein, Вы писали:
X>>>>но для целочисленных все же предпочитаю enum.
VF>>>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
NB>>static const double?
VF>enum { f = 3.14; } ???
X>>но для целочисленных все же предпочитаю enum.
VF>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
Здравствуйте, VladFein, Вы писали:
X>>но для целочисленных все же предпочитаю enum.
VF>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
Есть одно но. Согласно п.9.4.2/4 стандарта (п.9.4.2/3 в ст. 2003 г.), если даже объявление статической целочисленной константы — члена класса имеет инициализатор:
class A
{
static const int foo = 42;
};
все равно определение этого статического члена обязано быть сделано за пределами класса:
const int A::foo;
И в этом плане определение целочисленных констант при помощи enum имеет очевидное преимущество.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
X>>>но для целочисленных все же предпочитаю enum.
VF>>enum вместо static const <type> — это грязный хэк, доставщхийся нам со времён компиляторов, не умеющих инициализировать константные переменные по месту объявления.
R>Есть одно но. Согласно п.9.4.2/4 стандарта (п.9.4.2/3 в ст. 2003 г.), если даже объявление статической целочисленной константы — члена класса имеет инициализатор: R>все равно определение этого статического члена обязано быть сделано за пределами класса:
Здравствуйте, VladFein, Вы писали:
R>>И в этом плане определение целочисленных констант при помощи enum имеет очевидное преимущество.
VF>что не мешает этому оставаться грязным хэком...
Тут уже кто как ярлыки развесит...
--
Справедливость выше закона. А человечность выше справедливости.
L>static const int s_nLocalCounter = 1;
L>static const char s_szLocalName[] = "local name";
L>const int g_nGloabalCounter = 1;
L>
Во-первых,
const int g_nGloabalCounter = 1;
это то же самое, что и
static const int g_nGloabalCounter = 1;
поэтому не очень понятен принцип, по которому ты в одних случаях используешь префикс "s_", а в других "g_".
А во-вторых, современный C++ движется в сторону обобщенного программирования и обобщенных алгоритмов, к абстрагированию от конкретных типов. Поэтому ИМХО, использование префиксов, описывающих тип (а тем более связывание или storage duration) — это уже вчерашний день, а не best practices.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>А во-вторых, современный C++ движется в сторону обобщенного программирования и обобщенных алгоритмов, к абстрагированию от конкретных типов. Поэтому ИМХО, использование префиксов, описывающих тип (а тем более связывание или storage duration) — это уже вчерашний день, а не best practices.
А что не так в g_ и m_? И венгерская нотация — тоже нужная вещь.
Здравствуйте, Roman Odaisky, Вы писали:
RO>А что не так в g_ и m_? И венгерская нотация — тоже нужная вещь.
Во-первых, rg45 сравнивал "s_" и "g_", ошибочно утверждая, что между ними нет разницы (разница в видимости за пределами единицы трансляции).
Во-вторых, давайте начнём "спор" о венгерской нотации в отдельной теме, сразу в СВ
Здравствуйте, VladFein, Вы писали:
VF>Во-первых, rg45 сравнивал "s_" и "g_", ошибочно утверждая, что между ними нет разницы (разница в видимости за пределами единицы трансляции).
const объекты по умолчанию имеют внутреннее связывание (internal linkage), так же как и static переменные
VF>Во-вторых, давайте начнём "спор" о венгерской нотации в отдельной теме, сразу в СВ
+1
Здравствуйте, Roman Odaisky, Вы писали:
R>>А во-вторых, современный C++ движется в сторону обобщенного программирования и обобщенных алгоритмов, к абстрагированию от конкретных типов. Поэтому ИМХО, использование префиксов, описывающих тип (а тем более связывание или storage duration) — это уже вчерашний день, а не best practices.
RO>А что не так в g_ и m_? И венгерская нотация — тоже нужная вещь.
Думаю, как бы так ответить, чтоб и кратко и, в то же время, не провоцировать ненужных дискуссий. Скажем так, строго доказательства у меня нет, но есть вера в то, что без этих префиксов можно обойтись. Префикс m_ я и сам широко использую, но если подумать, то в хорошо спроектированном коде и он не нужен. От g_ и s_ так точно можно избавиться. Венгерская нотация — достаточно большой комплекс различных правил, дискутировать о нем можно долго. Я бы ограничился только рассмотрением вопроса кодирования типов переменных в их именах: "d", "n", "p", "sz" и прочие "абырвалги" — все эти шифровки нагружают лишними подробностями и утомляют при чтении. Хочется видеть максимально декларативный, самодокументированный и приближенный к человеческой речи код, где функции и переменные названы человеческими словами и описывают сущности предметной области.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, VladFein, Вы писали:
VF>Во-первых, rg45 сравнивал "s_" и "g_", ошибочно утверждая, что между ними нет разницы (разница в видимости за пределами единицы трансляции).
Никаких ошибочных утверждений не было. Согласно стандарту, как старому, так и новому, если переменная объявлена с модификатором const и при этом явно не объявлена как extern, то она получает внутренне связывание (т.е. static).
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Никаких ошибочных утверждений не было. Согласно стандарту, как старому, так и новому, если переменная объявлена с модификатором const и при этом явно не объявлена как extern, то она получает внутренне связывание (т.е. static).