在编译时将两个常量字符串(或数组)合并为一个常量字符串(或数组)
在 C# 和 Java 中,可以使用一个或多个其他常量字符串创建常量字符串。我试图在 C++ 中实现相同的结果(具体来说,在 C++0x 中),但不知道我将使用什么语法来实现它,如果这样的事情在 C++ 中是可能的。这是一个说明我想要做什么的示例:
#include <stdio.h>
const char array1[] = "Hello ";
const char array2[] = "world!\n";
const char array3[] = array1 + array2; // C++ doesn't like it when I try this
int main() {
printf(array3);
return 0;
}
有任何指示吗? (没有双关语。)
编辑:我也需要能够将其应用于整数数组 - 不仅仅是字符数组。然而,在这两种情况下,要组合的数组都是固定大小的并且是编译时常量。
In C# and Java, it's possible to create constant strings using one or more other constant strings. I'm trying to achieve the same result in C++ (actually, in C++0x, to be specific), but have no idea what syntax I would use to achieve it, if such a thing is possible in C++. Here's an example illustrating what I want to do:
#include <stdio.h>
const char array1[] = "Hello ";
const char array2[] = "world!\n";
const char array3[] = array1 + array2; // C++ doesn't like it when I try this
int main() {
printf(array3);
return 0;
}
Any pointers? (No pun intended.)
EDIT: I need to be able to apply this to integer arrays as well - not just char arrays. However, in both cases, the to-be-combined arrays will be fixed-size and be compile-time constants.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
所以......
你不想进行运行时串联。
您不想使用预处理器。
您想要使用常量和输出常量。
好的。但你不会喜欢它:
So...
You don't want to do run time concatenation.
You don't want to use the preprocessor.
You want to work with constants and output constants.
OK. But you're not going to like it:
使用字符串对象:
Use a string object:
在 C++0x 中,您可以执行以下操作:
我认为对于 C++98 中的 STL 容器没有任何方法可以执行此操作(您可以执行
v3
的附加部分,但您可以在 C++98 中不要使用v1
和v2
的初始化列表),并且我认为没有任何方法可以对 C++ 中的原始数组执行此操作0x 或 C++98。In C++0x you can do the following:
I don't think there's any way to do this for STL containers in C++98 (the addition part for
v3
you can do, but you can't use the initializer lists forv1
andv2
in C++98), and I don't think there's any way to do this for raw arrays in C++0x or C++98.在这种情况下,预处理器通常会很方便
注意:不需要
+
。In cases like this preprocessor often comes handy
Note: no
+
necessary.我看了你的问题,发现没有人真正回答你的问题。我花了一整天的时间来回答这个问题,但无论如何我的工作都需要它。
我的工作需要
constexpr
,我写下答案时就考虑到了这一点。你的工作没有具体说明这一点,但这不会有什么坏处。什么不起作用;即我的第一次尝试
(我在一台 10 年前的 PowerPC Mac 上使用来自 MacPorts 的 GCC-4.7。)
您可以轻松地将 (C++11) 可变参数函数参数列表转换为任何类型的元组:
(< code>ce_forward 函数模板就像
std::forward
一样,只是我明确地将其设为constexpr
。)(当我没有输入
Destination 时
在正文中,我的编译器给出了与无法使用std::initialization_list
初始化目标相关的错误,因此我现在的表单应该适用于任何聚合或构造函数。形成目标类型支持的形式。)但是我们需要首先走另一条路,然后使用我上面的代码翻译回来。我尝试了这样的代码:(
因为我也需要两个源,所以我制作了这个函数的更大版本。)
当我实际运行这段代码时,我的计算机在一小时后因超出虚拟内存而崩溃。我猜这会导致无限循环或其他原因。 (或者也许它是有限的,但对于我古老的系统来说太多了。)
我的第二次尝试
是这样搜索的,直到找到可能有用的东西:
并从这些内容和我读到的其他内容中拼凑出一个解决方案:在编译时解析字符串 - 第一部分 。基本上,我们使用上面的
initialize
函数模板的变体;我们不使用纯粹基于函数可变参数的初始化器,而是使用模板可变参数的映射。最简单的映射源是非负整数:
index_tuple
类模板是我们将传递用于映射的内容,而build_indices
类模板则将index_tuple< /code> 以正确的格式实例化:
我们使用函数模板创建
index_tuple
对象:我们使用所述
index_tuple
对象来贡献函数模板的模板头:第三个参数没有名称,因为我们不需要该对象本身。我们只需要标头中的“std::size_t ...Indices”。我们知道展开后会变成“0,1,...,X”。我们会将有序扩展提供给函数调用,该函数调用将扩展为所需的初始值设定项。作为示例,让我们看一下上面函数的定义:
我们将返回一个
array
,其中第一个元素为get_strchr<0>(f,s)
,第二个为get_strchr<1>(f,s)
,依此类推。请注意,此函数名称以“_impl”结尾,因为我隐藏了index_tuple
的使用,并通过调用公共版本来确保正确的基本情况:并且您可以尝试这样编码:
有一些微妙之处留意。
const(expr) char str[] = "Whatever";
声明必须使用[]
而不是*
,以便编译器识别您的对象作为内置数组,而不是作为指向运行时长度的未知(固定)内存的指针。std::array
作为替代。问题是当您必须将结果用于以后的合并时。std::array
对象必须具有适当的内置数组类型的公开可用的非静态数据成员,但该成员的名称未在标准中指定,也可能没有指定持续的。因此,您必须创建一个类似的std::array
工作才能正式避免黑客攻击。char
数组,其中最后一个元素必须是'\0'
。从字符串读取时必须跳过这些NUL
值,但在写入字符串时添加这些值。这就是我的代码中出现奇数 1 和 2 的原因。对于一般数组连接(包括非字符串char
),必须读取每个数组中的每个元素,并且不应将额外的元素添加到组合数组中。哦,这是
get_strchr
的定义:(我希望你能读到这篇文章。)
I took a look at your question, and noticed that no one really answered it. My diversion to answer it took all day to perfect, but I needed it anyway for my work.
My work needs
constexpr
, and I wrote the answer with that in mind. Your work doesn't specify that, but it can't hurt.What didn't work; i.e. my first try
(I'm using GCC-4.7, from MacPorts, on a 10-year old PowerPC Mac.)
You can easily turn a (C++11) variadic function parameter list to any kind of tuple:
(The
ce_forward
function template is just likestd::forward
, except I explicitly made itconstexpr
.)(When I didn't put
Destination
in the body, my compiler gave me errors relating to the destination not being able to be initialized with astd::initialization_list
; so the form I have now should work with any aggregate or constructor form the destination type supports.)But we need to initially go the other way, then use my code above to translate back. I tried code like this:
(Since I needed two sources too, I made a bigger version of this function.)
When I actually ran this code, my computer crapped out after an hour from exceeding virtual memory. I guess this causes an infinite loop or something. (Or maybe it's finite, but too much for my ancient system.)
My second try
I scoured S.O. until I found stuff that could be useful:
and pieced a solution from those and something else I read: Parsing strings at compile-time — Part I. Basically, we use a variant of my
initialize
function template above; instead of basing the initializers purely off function variadic parameters, we use a mapping from template variadic parameters.The easiest mapping source is the nonnegative integers:
The
index_tuple
class template is what we'll be passing around for mapping, while thebuild_indices
class template puts theindex_tuple
instantiations in the right format:We create
index_tuple
objects with a function template:We use said
index_tuple
objects for their contribution to a function template's template header:The third parameter doesn't get a name because we won't need the object itself. We just need the "std::size_t ...Indices" in the header. We know that will turn into a "0, 1, ..., X" when expanded. We'll feed that orderly expansion into a function call that gets expanded into the required initializers. As an example, let's look at the definition of the function above:
We'll be returning an
array
with the first element asget_strchr<0>(f,s)
, the second asget_strchr<1>(f,s)
, and so on. Note that this function name ends with "_impl" because I hide the use ofindex_tuple
and ensure a proper base case by calling the public version:And you can try to code as so:
There are some subtleties to watch for.
const(expr) char str[] = "Whatever";
have to use[]
instead of*
so the compiler recognizes your object as a built-in array, and not as a pointer to unknown (fixed) memory of run-time length.std::array
as a substitute. The problem is when you have to use the result for a later merging. Astd::array
object has to have a publicly available non-static data member of the appropriate built-in array type, but the name of that member is not specified in the standard and probably isn't consistent. So you have to create astd::array
work-alike to officially avoid hacks.char
array where the last element must be'\0'
. ThoseNUL
values must be skipped when reading from strings but added when writing one. That why the odd 1's and 2's appear in my code. For general array joins (including non-stringchar
ones), every element in every array must be read, and no extra elements should be added to the combined array.Oh, here's the definition of
get_strchr
:(I hope you get to read this.)