У нас довольно большой проект, который определяет static const std::string
s в нескольких местах для использования в качестве имен параметров; некоторые из них должны быть объединены во время статической инициализации:
foo.h:
struct Foo {
static const std::string ParamSuffix;
};
foo.cpp:
const std::string Foo::ParamSuffix = ".suffix";
bar.h:
struct Bar {
static const std::string ParamPrefix;
};
bar.cpp:
const std::string Bar::ParamPrefix = "prefix";
baz.h:
struct Baz {
static const std::string ParamName;
};
baz.cpp:
const std::string Baz::ParamName = Bar::ParamPrefix + Foo::ParamSuffix;
Проблема, очевидно, заключается в «фиаско статической инициализации», так как не определено, в каком порядке static const
члены инициализируются.
Мне не нравится обычное решение, то есть заменить все эти переменные на функции, потому что
В настоящее время я не могу использовать C ++ 11, что облегчит его constexpr
особенность (я думаю).
Вопрос в том: Есть ли хитрость, которая позволила бы мне объединить static const std::string
s (или объекты-обертки или что-то еще) для инициализации другого static const std::string
?
Вопрос в том, есть ли какой-нибудь трюк, который позволил бы мне объединить статический const std :: strings (или объекты-обертки или что-то еще) для инициализации другого статического const std :: string?
Нет тривиальных, кроме того, который вам не нравится: создайте функции для статических строк.
Однако существуют нетривиальные альтернативы (например, замените все жестко запрограммированные строки контейнером строк / картой строк и загрузите карту при запуске приложения).
Однако я рекомендую использовать статические функции (решение, которое вы отклонили).
Почему вы так думаете std::string const
это каким-то особенным? (подсказка: это не так) Даже если бы вы могли использовать C ++ 11 constexpr
это не поможет, потому что вы не можете сделать std:string
константные выражения (им может потребоваться выделить память, которая не является жизнеспособным константным выражением). Вы можете иметь дело со строковым классом, используемым для constexpr
что может быть сделано для преобразования в std::string
но я не уверен, что их можно объединить для создания нового constexpr
,
Что вы, возможно, можете сделать, это извлечь те строки, которые вам нужно использовать как часть конкатенации, и предоставить их значение в виде макроса. Строковые литералы (которые имеют тип char const[N]
для подходящего N
) можно объединить, просто поместив их рядом друг с другом:
// foo.h
#define FOO_PARAM_SUFFIX ".suffix"struct Foo {
static const std::string ParamSuffix;
};
// foo.cpp:
std::string const Foo::ParamSuffix(FOO_PARAM_SUFFIX);
// bar.h:
#define BAR_PARAM_SUFFIX "prefix"struct Bar {
static std::string const ParamPrefix;
};
// bar.cpp:
std::string const Bar::ParamPrefix(BAR_PARAM_SUFFIX);
// baz.h:
#include "foo.h"#include "bar.h"#define BAZ_PARAM_NAME BAR_PARAM_PREFIX FOO_PARAM_SUFFIX
struct Baz {
static std::string const ParamName;
};
// baz.cpp:
#include "foo.h"#include "bar.h"std::string const Baz::ParamName(BAR_PARAM_PREFIX FOO_PARAM_SUFFIX);
Я бы догадался, что BAZ_PARAM_NAME
не используется где-либо еще, и в этом случае его также не нужно определять: он определен просто для того, чтобы показать, что это можно сделать. Инициализация Bar::ParamName
предполагает, что BAZ_PARAM_NAME
не определено
Когда текст не зависит от другой переменной, вы можете рассмотреть возможность изменения типа с const std::string
к const char
массив аля const char param_prefix[] = "prefix";
— вполне может быть менее принудительное изменение в использовании клиента, но это может скрыть новые временные std::string
должны быть (или непреднамеренно) созданы каждый раз, когда они используются.
Проверьте свою систему, но вы почти наверняка можете безопасно использовать эти const char
переменные в построении других std::string
константы — но вам не повезло обязательно-std::string
зависимости от других std::string
s.
Если слишком сложно распутать существующие значения вconst
—char
а также std::string
которые зависят только от const
—char
с, или это просто не покрывает достаточно ваших дел, тогда стоит заняться оптовыми модификациями каждой константы.
Привлекательность оболочек в том, что вы можете сохранить тип и семантику использования одинаковыми. Для этого вам нужно заменить все эти инициализированные во время выполнения строки своим собственным типом, который координирует два центральных списка: — инициализированные объекты и ожидающие объекты. Шаблон наблюдателя является подходящим, или вы могли бы, например, зарегистрировать список обратных вызовов и завершить инициализацию путем main()
вызывая их до тех пор, пока все они не укажут на успех: если известно, что хотя бы некоторая инициализация объекта является статической, это может позволить одному объекту проверить состояние инициализации другого, что позволит избежать того, чтобы конструкторы регистрировали свое завершение.
Если это возможно с помощью более интеллектуальных инструментов изменения исходного кода (например, awk) — может быть, лучше просто изменить константы, которые будут возвращаться функциями.