能够在 C++ 编译期间创建和操作字符串有几个有用的应用程序。虽然可以在 C++ 中创建编译时字符串,但这个过程非常繁琐,因为字符串需要声明为可变的字符序列,例如
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
字符串连接、子字符串提取等操作可以很容易地实现为对字符序列的操作。 是否可以更方便地声明编译时字符串?如果没有,是否有一项提案可以方便地声明编译时字符串?
为什么现有方法会失败
理想情况下,我们希望能够如下声明编译时字符串:
// Approach 1
using str1 = sequence<"Hello, world!">;
或者,使用用户定义的文字,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
其中 decltype(str2)
将有一个 constexpr
构造函数。利用您可以执行以下操作的事实,可以实现方法 1 的更混乱版本:
template <unsigned Size, const char Array[Size]>
struct foo;
但是,数组需要有外部链接,所以要让方法 1 起作用,我们必须编写如下内容:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
不用说,这很不方便。方法2实际上是不可能实现的。如果我们要声明一个 ( constexpr
) 文字运算符,那么我们将如何指定返回类型?由于我们需要操作符返回一个可变的字符序列,所以我们需要使用 const char*
参数来指定返回类型:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
这会导致编译错误,因为 s
不是 constexpr
。尝试通过执行以下操作来解决此问题并没有多大帮助。
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
该标准规定,这种特定的文字运算符形式是为整数和浮点类型保留的。虽然 123_s
可以工作,但 abc_s
不会。如果我们完全放弃用户定义的文字,而只使用常规的 constexpr
函数会怎样?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
和以前一样,我们遇到的问题是数组,现在是 constexpr
函数的参数,它本身不再是 constexpr
类型。
我相信应该可以定义一个 C 预处理器宏,它将字符串和字符串的大小作为参数,并返回由字符串中的字符组成的序列(使用 BOOST_PP_FOR
,字符串化,数组下标等)。但是,我没有时间(或足够的兴趣)来实现这样的宏 =)
原文由 void-pointer 发布,翻译遵循 CC BY-SA 4.0 许可协议
我还没有看到任何东西可以与 Scott Schurr 在 C++ Now 2012 上发表 的
str_const
的优雅相媲美。它确实需要constexpr
。以下是您可以如何使用它以及它可以做什么:
它并没有比编译时范围检查更酷!
使用和实现都没有宏。并且对字符串大小没有人为的限制。我会在这里发布实现,但我尊重 Scott 的隐含版权。实施是在他的演示文稿的一张幻灯片上链接到上面。
更新 C++17
自从我发布这个答案以来的几年里,
std::string_view
已经成为我们工具箱的一部分。以下是我将如何使用string_view
重写上述内容: