C++ 字符串的静态初始化顺序和串联
我们有一个相当大的项目,它在几个地方定义了C++ 字符串的静态初始化顺序和串联,c++,string,string-concatenation,static-initialization,C++,String,String Concatenation,Static Initialization,我们有一个相当大的项目,它在几个地方定义了static const std::strings作为参数名;其中一些需要在静态初始化期间连接: foo.h: struct Foo { static const std::string ParamSuffix; }; foo.cpp: const std::string Foo::ParamSuffix = ".suffix"; B.h: struct Bar { static const std::string ParamPrefix;
static const std::string
s作为参数名;其中一些需要在静态初始化期间连接:
foo.h:
struct Foo {
static const std::string ParamSuffix;
};
foo.cpp:
const std::string Foo::ParamSuffix = ".suffix";
B.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
成员初始化的顺序
我不喜欢通常的解决方案,即用函数替换所有这些变量,因为
constepr
特性(我想)会让事情变得更简单
问题是:有没有什么技巧可以让我连接
静态常量std::string
s(或包装器对象或任何东西)来初始化另一个静态常量std::string
?为什么你认为std::string const
在任何方面都是特殊的?(提示:并非如此)即使您可以使用C++11的constexpr
,也不会有帮助,因为您无法生成std:string
s常量表达式(它们可能需要分配内存,而内存不是可行的常量表达式)。您可以处理用于constexpr
的类似字符串的类,该类可以转换为std::string
,但我不确定这些类是否可以连接起来生成新的constexpr
您可能能够做的是提取那些您需要作为连接的一部分使用的字符串,并以宏的形式提供它们的值。字符串文字(对于合适的N
,其类型为char const[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
问题是:有没有什么技巧可以让我连接static const std::string(或包装器对象或其他什么)来初始化另一个static const std::string
除了你不喜欢的一个,没有什么琐碎的:为静态字符串创建函数
但也有一些非常重要的替代方案(例如,用字符串容器/字符串映射替换所有硬编码字符串,并在应用程序启动时加载映射)
我的建议是使用静态函数(您拒绝的解决方案)。< /P> < P>当文本不依赖于另一个变量时,您可以考虑将类型从“代码> const STD::String 改为<代码> const char < /COD>数组ALA <代码> const char PARAMP-前缀[]=“前缀”;<代码>-对客户端使用的强制更改可能较少,但这可能会隐藏每次使用时必须(或无意中)创建的新临时
std::string
s
检查您的系统,但几乎可以肯定,您可以在构造其他std::string
常量时安全地使用这些const char
变量-但您的运气不好,因为它必然依赖于其他std::string
s
如果很难将现有值分解为只能依赖于const
-char
或std::string
s的can-be-const
-char
的can-be-const
和char,那么对每个常量的全面修改都是值得追求的
包装器的吸引力在于可以保持使用的类型和语义相同。为此,您需要将所有这些运行时初始化字符串替换为您自己的类型,该类型协调两个中心列表:-初始化对象和等待对象。观察者模式是合适的,或者您可以注册回调列表并通过循环调用main()
完成初始化,直到它们都指示成功:如果已知至少部分对象初始化是静态的,则允许一个对象测试另一个对象的初始化状态,这样可以避免让施工人员登记完工情况
如果有更智能的源代码修改工具(如awk)的帮助,最好是简单地更改常量,使其干净地由函数返回。在使用宏之前,我仍然可以使用const char Foo::ParamSuffix[]=“.suffix”
etc,并在连接到Baz::ParamName
之前将其转换为std::string
,但我想要一个到处都是一致类型或至少隐藏丑陋的解决方案。@arne:你没有抓住重点。。。预处理器可以在源代码中一个接一个地放置带引号的字符串,然后编译器将它们连接起来形成一个新的字符串文字(即ASCIIZ C样式的字符串“常量”)。由于Dietmar在回答中提到的原因,您在编译时不能使用std::string
s执行任何操作。@arne:const char x[]=“…”代码>无法连接。我也不确定它们是否会足够早地初始化(即,在动态初始化之前或作为动态初始化的一部分)。这些对象很可能与std::string
对象有相同的问题。@Dietmar:const char x[]
解决方案在我们尝试时起作用了——字符串的内容被逐字放入可执行文件的只读部分。将它们转换为std::string
(正如我前面提到的)并将它们连接起来(正如我前面提到的)效果非常好。“不过还是很难看。”@TonyD我知道预处理器可以做这样的事情。由于名称空间pol,我仍然觉得解决方案很难看