статический порядок инициализации и конкатенации строк

У нас довольно большой проект, который определяет static const std::strings в нескольких местах для использования в качестве имен параметров; некоторые из них должны быть объединены во время статической инициализации:

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 члены инициализируются.

Мне не нравится обычное решение, то есть заменить все эти переменные на функции, потому что

  1. Там много этих переменных, то есть много изменений кода
  2. Конкатенации требуют специальных функций, что делает кодовую базу несовместимой и еще более уродливой

В настоящее время я не могу использовать C ++ 11, что облегчит его constexpr особенность (я думаю).

Вопрос в том: Есть ли хитрость, которая позволила бы мне объединить static const std::strings (или объекты-обертки или что-то еще) для инициализации другого static const std::string?

3

Решение

Вопрос в том, есть ли какой-нибудь трюк, который позволил бы мне объединить статический const std :: strings (или объекты-обертки или что-то еще) для инициализации другого статического const std :: string?

Нет тривиальных, кроме того, который вам не нравится: создайте функции для статических строк.

Однако существуют нетривиальные альтернативы (например, замените все жестко запрограммированные строки контейнером строк / картой строк и загрузите карту при запуске приложения).

Однако я рекомендую использовать статические функции (решение, которое вы отклонили).

4

Другие решения

Почему вы так думаете 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 не определено

2

Когда текст не зависит от другой переменной, вы можете рассмотреть возможность изменения типа с const std::string к const char массив аля const char param_prefix[] = "prefix"; — вполне может быть менее принудительное изменение в использовании клиента, но это может скрыть новые временные std::stringдолжны быть (или непреднамеренно) созданы каждый раз, когда они используются.

Проверьте свою систему, но вы почти наверняка можете безопасно использовать эти const char переменные в построении других std::string константы — но вам не повезло обязательно-std::string зависимости от других std::strings.

Если слишком сложно распутать существующие значения вconstchar а также std::stringкоторые зависят только от constcharс, или это просто не покрывает достаточно ваших дел, тогда стоит заняться оптовыми модификациями каждой константы.

Привлекательность оболочек в том, что вы можете сохранить тип и семантику использования одинаковыми. Для этого вам нужно заменить все эти инициализированные во время выполнения строки своим собственным типом, который координирует два центральных списка: — инициализированные объекты и ожидающие объекты. Шаблон наблюдателя является подходящим, или вы могли бы, например, зарегистрировать список обратных вызовов и завершить инициализацию путем main() вызывая их до тех пор, пока все они не укажут на успех: если известно, что хотя бы некоторая инициализация объекта является статической, это может позволить одному объекту проверить состояние инициализации другого, что позволит избежать того, чтобы конструкторы регистрировали свое завершение.

Если это возможно с помощью более интеллектуальных инструментов изменения исходного кода (например, awk) — может быть, лучше просто изменить константы, которые будут возвращаться функциями.

2
По вопросам рекламы [email protected]