有没有办法在 for 循环初始值设定项中定义两种不同类型的变量?
你可以在for循环中定义2个相同类型的变量:
int main() {
for (int i = 0, j = 0; i < 10; i += 1, j = 2*i) {
cout << j << endl;
}
}
但是定义不同类型的变量是非法的:
int main() {
for (int i = 0, float j = 0.0; i < 10; i += 1, j = 2*i) {
cout << j << endl;
}
}
有没有办法做到这一点? (我不需要在循环内使用 i
,只需使用 j
。)
如果您有完全破解且晦涩的解决方案,对我来说没关系。
在这个人为的示例中,我知道您可以对两个变量使用 double 。 我正在寻找一个普遍的答案。
请不要建议将任何变量移到 for 主体之外,可能对我来说不可用,因为它是一个迭代器,必须在循环之后立即消失,并且 for 语句将包含在我的 foreach
宏:
#define foreach(var, iter, instr) { \
typeof(iter) var##IT = iter; \
typeof(iter)::Element var = *var##IT; \
for (; var##_iterIT.is_still_ok(); ++var##IT, var = *var#IT) { \
instr; \
} \
}
可以这样使用:
foreach(ii, collection, {
cout << ii;
}).
但我需要这样使用的东西:
foreach(ii, collection)
cout << ii;
请不要引入任何运行时开销(但编译可能会很慢)。
You can define 2 variables of the same type in a for loop:
int main() {
for (int i = 0, j = 0; i < 10; i += 1, j = 2*i) {
cout << j << endl;
}
}
But it is illegal to define variables of different types:
int main() {
for (int i = 0, float j = 0.0; i < 10; i += 1, j = 2*i) {
cout << j << endl;
}
}
Is there a way to do this? (I don't need to use i
inside the loop, just j
.)
If you have totally hacked and obscure solution, It's OK for me.
In this contrived example I know you could just use double
for both variables. I'm looking for a general answer.
Please do not suggest to move any of the variables outside of for body, probably not usable for me as one is an iterator that has to disappear just after the loop and the for statement is to be enclosed in my foreach
macro:
#define foreach(var, iter, instr) { \
typeof(iter) var##IT = iter; \
typeof(iter)::Element var = *var##IT; \
for (; var##_iterIT.is_still_ok(); ++var##IT, var = *var#IT) { \
instr; \
} \
}
It can be used thus:
foreach(ii, collection, {
cout << ii;
}).
But I need something that will be used like that:
foreach(ii, collection)
cout << ii;
Please do not introduce any runtime overhead (but it might be slow to compile).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
这是一个使用 boost 预处理器的版本(这只是为了好玩。有关实际答案,请参阅上面 @kitchen 的答案):
第一部分指定一系列声明:
(a)(b)...< /代码>。 后面声明的变量可以引用前面声明的变量。 第二部分和第三部分照常进行。 当第二部分和第三部分出现逗号时,可以使用括号来防止它们分隔宏参数。
我知道有两个技巧用于声明变量,这些变量稍后在宏外部添加的复合语句中可见。 第一个使用条件,例如 if:
Then
k
可见。 当然,它总是必须评估为false
。 所以我们不能使用它。 另一种上下文是这样的:这就是我要在这里使用的。 我们必须注意仅对
COMPOUND_STATMENT
进行一次迭代。 执行增量和条件检查的实际for
循环必须出现在末尾,因此附加的复合语句与其相关。它创建了一堆
for
语句,每个语句都嵌套在另一个语句中。 它扩展为:Here is a version using boost preprocessor (This is just for fun. For the real-world answer, see @kitchen's one above):
The first part specifies a sequence of declarations:
(a)(b)...
. The variables declared later can refer to variables declared before them. The second and third part are as usual. Where commas occur in the second and third parts, parentheses can be used to prevent them to separate macro arguments.There are two tricks known to me used to declare variables that are later visible in a compound statement added outside a macro. The first uses conditions, like an if:
Then
k
is visible. Naturally, it always have to evaluate tofalse
. So it can't be used by us. The other context is this one:That's what i'm going to use here. We'll have to watch to only make one iteration of
COMPOUND_STATEMENT
. The actualfor
loop that does the increment and condition checking has to come at the end, so the appended compound statement appertains to it.It's creating a bunch of
for
statements, each nested into another one. It expands into:嗯,这很丑。 但你可以使用pair。
Well, it's ugly. But you could use pair.
你可以这样做:
You could do this:
也许我太笨了,但为什么你还要声明浮动呢? 无论如何,当你离开循环时,你只需“扔掉它”即可。 正确的?
为什么需要 j?
Maybe I'm being dense, but why do you even have to declare the float? You just "throw it away" when you leave the loop anyways. Right?
Why do you need j?
根据您给出的要求,我能想到的最简单的代码是:
您仅使用 f 作为 i 值的两倍。 生命周期仅限于循环,并且(至少在您提供的简化问题中)浮点数的创建成本低廉(与分配成本完全相同)。
如果构建真正的浮点数(我假设因为 i 不是真正的 int,f 也可能不是浮点数)比重新分配值要昂贵得多,那么封装在内部的其他解决方案一对额外的大括号来限制范围将是最好的选择。
With the requirements you give the simplest code I can think of is:
You only use f as twice the value of i. The lifetime is limited to the loop and (at least in the simplified question you provide) floats are cheap to create (exactly as cheap as to assign).
If construction of the real float (I am assuming that since i is not really an int, f may not be a float either) is much more expensive than reassigning the value, then the other solutions of encapsulating inside an extra pair of curly braces to limit scope would be the best option.
您仍然可以这样做,并将整个内容放在花括号中以使额外的变量超出范围。
这样
j
将在循环之后立即超出范围。You could still do that, and put the whole thing in curly braces to make the extra variable go out of scope.
This way
j
would go out of scope right after the loop.这也很丑陋,但也提供了一些通用方法,用于在 for 循环中声明具有给定名称和类型的多个变量
This one is also ugly, but provides also some general way for declaring multiple variables with some given name and types in a for-loop
编辑:问题再次改变。 现在的问题明确想要实现一个 foreach 循环。 最简单的答案:
将变量注入代码块
这并不是一个答案,而是展示一种将变量注入代码块的更通用的技术。 OP 尝试定义的宏似乎可能会使用,即使它确实会产生一些开销
有几个地方可以定义具有不同作用域的变量。 您可以在任何代码块内定义变量,其生命周期将到该特定块的末尾。 您可以在 for 循环的括号中定义变量,其范围将是循环块。 您还可以在 if 块内定义变量,其范围将是 if 的范围(包括 else 子句)。
您可以组合上面的这些选项来从外部创建并将变量注入到代码块中,而无需创建寿命超过代码块的变量。 一个实际的例子是定义一个 foreach 循环(简化为仅在 STL 容器上工作。调用语法为:
语义与其他语言中的 foreach 类似:x 引用容器中的每个元素,因此该函数实际上将每个元素加倍 。
现在是简化宏的代码:
将宏推广到任何容器和类型都需要一些脱离问题上下文的元编程,但它的工作原理(我希望)不应该太复杂 。
外部 for 遍历容器,在每次迭代中,我们仅执行一次定义迭代变量(示例代码中的 int & x )的 for 我们需要一个条件来控制内部循环的迭代次数 (1),并且该条件是用 if 注入的,我们选择使 if 失败,以便我们可以确保用户这样做。如果她在循环后编写 else,则不会得到意外的结果...宏很棘手。
EDIT: Question has changed once more. The question now explicitly wants to implement a foreach loop. The simplest answer:
Injecting a variable into a code block
This is not intended as an answer, but to show a more general technique for injecting a variable into a code block. It seems as if the macro the OP is trying to define might use, even if it does incur in some overhead
There are a couple of places where you can define a variable with different scopes. You can define a variable inside any code block, and its lifespan will be to the end of that particular block. You can define a variable in the parenthesis of a for loop and the scope will be the loop block. You can also define a variable inside an if block and its scope will be that of the if (including the else clause).
You can combine those options above to create externally and inject variables into a code block without creating a variable whose lifespan exceeds that of the block. A practical example would be defining a foreach loop (simplified to work only on STL containers. The calling syntax would be:
With semantics similar to foreach in other languages: x gets referenced to each element in the container, so that the function actually doubles each value inside the integer vector.
Now the code of the simplified macro:
Generalizing the macro for any container and type requires some metaprogramming that falls out of the context of the question, but the idea of how it works (I hope) should not be too hard to follow.
The external for iterates over the container, in each iteration we execute another for only once defining the iterating variable (int & x in the sample code). We need a condition to control the number of iterations (1) of the internal loop, and that condition is injected with an if. We choose to make the if fail so that we can ensure that the user does not get unexpected results if she writes an else after the loop... macros are tricky.
如果您在使用宏时遇到问题,有一个标准的
do..while
技巧可以完美地发挥作用:按如下方式使用它:
它很丑陋,但它可以满足您的要求:
i 的范围
和j
受到宏中的do..while
循环的限制,并且它需要在末尾有一个分号,所以你不会被将其放在 if/else 语句的谓词中。If you're having trouble with macros, there's a standard
do..while
trick that works perfectly:Use it as follows:
It's ugly, but it does what you want: the scope of
i
andj
is limited by thedo..while
loop from the macro, and it requires a semicolon at the end, so you won't get bitten by putting it in the predicate of an if/else statement.变量在块之后“消失”。
The variables "disappear" after the block.
这将使迭代器(或者在本例中为浮动)在不再需要时消失:
This will make the iterator (or in this case, float) disappear when it's no more needed:
为什么不在 for 循环之外声明并初始化变量呢? 您仍然可以像现在一样进行测试和增量。
Why don't you just declare and initialize your variables outside of the for loop? You can still test and increment as you have it now.
你说
i
是你自己的类型,你只需要从i
生成j
,对吧? 简单的。 将成员函数添加到i
的类中以生成j
值,并始终使用该值。 如果需要,您甚至可以创建一个宏来“隐藏”对该成员函数的调用。 :-)You say the
i
is your own type, and you just need to generatej
out ofi
, right? Easy. Add a member function toi
's class to generate thej
value, and use that always. You can probably even make a macro to "hide" the call to that member function, if you want. :-)