3

我们有一个相当大的项目,它在几个地方定义了static const std::strings 用作参数名称;其中一些需要在静态初始化期间连接:

富.h:

struct Foo {
  static const std::string ParamSuffix;
};

foo.cpp:

const std::string Foo::ParamSuffix = ".suffix";

酒吧.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 (或包装对象或其他)来初始化另一个 sstatic const std::string吗?

4

3 回答 3

3

问题是:是否有任何技巧可以让我连接 static const std::strings(或包装对象或其他)来初始化另一个静态 const std::string?

除了您不喜欢的之外,没有琐碎的:为静态字符串创建函数。

虽然有一些重要的替代方案(例如,用字符串容器/字符串映射替换所有硬编码的字符串,并在应用程序启动时加载映射)。

不过,我的建议是使用静态函数(您拒绝的解决方案)。

于 2014-01-03T10:11:08.007 回答
2

当文本不依赖于另一个变量时,您可能会考虑将类型从更改const std::stringconst char数组 ala const char param_prefix[] = "prefix";- 客户端使用的强制更改可能会更少,但这可能会隐藏std::string必须(或无意中)创建的新临时 s使用它们的时间。

检查你的系统,但你几乎可以肯定地const char在其他常量的构造中安全地使用这些变量std::string——但你运气不好必然——std::string依赖于其他std::strings。

如果很难将现有值解开为仅依赖于 - s 的 can-be- 和 s const,或者char只是没有涵盖足够多的情况,那么对每个常量进行大规模修改都是值得追求的。std::stringconstchar

包装器的吸引力在于您可以保持使用的类型和语义相同。为此,您需要将所有这些运行时初始化的字符串替换为您自己的类型,该类型协调两个中央列表:- 初始化对象和等待对象。观察者模式是合适的,或者您可以例如注册一个回调列表并通过循环main()调用它们来完成初始化,直到它们都表明成功:如果至少一些对象初始化已知是静态的,那么这可能允许一个对象进行测试另一个的初始化状态,这将避免必须让构造函数注册它们的完成。

如果在更智能的源代码修改工具(例如 awk)的帮助下可能的话 - 最好简单地更改常量以由函数干净地返回。

于 2014-01-03T10:17:06.533 回答
2

为什么你认为这std::string const有什么特别之处?(提示:不是)即使您可以使用 C++11 constexpr,它也无济于事,因为您无法制作std:strings 常量表达式(它们可能需要分配不是可行的常量表达式的内存)。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

于 2014-01-03T09:38:14.583 回答