我们说我有这段代码:
for (int i = 0; i < x.size(); i++) {
auto &in = input[i];
auto &func = functions[i];
auto &out = output[i];
// pseudo-code from here:
unaccessiable(i);
i = func(in); // error, i is not declared
out = func(i); // error, i is not declared
// useful when you mistake in/out for i
}
我需要实现在代码中的某一行之后无法访问或使用变量的效果。 (在此代码中,unaccessiable(i)
之后)
具体来说,我想禁用for循环的迭代器。
注意:这仅用于代码正确性,除此之外什么都没有。所以lambdas(非编译时解决方案)只是性能阻碍。
答案 0 :(得分:6)
使名称在块中途无法使用的最简单方法是将其声明为struct
:
for (int i = 0; i < x.size(); i++) {
auto &in = input[i];
auto &func = functions[i];
auto &out = output[i];
// pseudo-code from here:
struct i; // ←
i = func(in); // error, i is a type
// useful when you mistake out for i
}
或者你可以把代码放在&#34; here&#34;在嵌套块中,您可以将i
重新声明为某种类型的变量,这可能会提供更好的诊断。
答案 1 :(得分:2)
想到的一种方法是:
for (int i = 0; i < x.size(); i++) {
auto &in = input[i];
auto &func = functions[i];
auto &out = output[i];
{
struct{} i;
// ...
i = func(in); // error
// useful when you mistake out for i
}
}
匿名类型不会与任何返回类型或参数类型兼容。 (Variadic函数除外)
(感谢LyingOnTheSky建议使用匿名结构。)
答案 2 :(得分:1)
您可以将使用i
的部分放入其自己的块中。
for (int counter = 0; counter < x.size(); counter++) {
{
auto i = counter;
auto &in = input[i];
auto &func = functions[i];
auto &out = output[i];
} // i goes out of scope here
i = func(in); // error, i is not declared
// useful when you mistake out for i
}
现在i
仅在内部块中定义。
答案 3 :(得分:1)
尽管您想要应用于循环的限制没有意义,但我会重写您的循环以确保没有人错误地使用计数器:
for(int i = 0;;) //whatever guard
{
DoRequiredAction(i);
}
然后你的DoRequiredAction
方法不必修改循环计数器。
答案 4 :(得分:0)
不知道是否适用:
#include <stdio.h>
int main(void)
{
for (int i = 0, j; i < 20; i=++j)
{
j=i;
printf("%d - ", i);
i = 25;
}
printf("\n");
return 0;
}
输出
0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 -
正如您所看到的,无论使用i
内部循环范围做了什么,由于在循环开始时将i
值备份到j
。
答案 5 :(得分:0)
我不会讨好你,但这不符合你的预期:
#undef
,但它只适用于预处理器符号我从您的评论中了解您的隐藏要求:
我不希望别人错误地在循环中使用循环的迭代器。 它发生在我们身上太多次了。
但无论采用何种方法,for
语句的设计方式都是在循环中总是有可能使循环变量变得棘手
幸运的是,可以有一个解决方案来防止这种情况发生。但是你必须围绕基于容器的习语来重构你的代码。
然后您可以选择range-for,这样任何人都无法干预您的迭代器:
for (auto &x : mycontainer) { // where mycontainer is a standard or a custom container
const auto &in = x.input; // ok, avoid they srcew up your input as well ;-)
const auto &func = x.functions;
auto &out = x.output;
...
// haha : how can anyone screw the iterator now ? :-)
}
答案 6 :(得分:0)
如果您不希望变量可访问,为什么要创建它?
package com.example.swing;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.time.LocalDateTime;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class ExitDelay {
public static void main(String[] args){
Runtime.getRuntime().addShutdownHook(new Thread(() -> System.err.println(LocalDateTime.now() + " SHUTDOWN") ));
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setSize(1280,720);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter(){
@Override
public void windowClosed(WindowEvent e){
System.err.println(LocalDateTime.now() + " CLOSE");
// Do all required cleanup stuff.
// check that threads are done, close files, commit transactions etc.
// ...
System.exit(0);
}
});
frame.setVisible(true);
});
}
}
答案 7 :(得分:0)
这是另一种方式 - 使用zip迭代器而不是使用索引寻址:
这样,在管道之后,问题可以表达出来:
extern std::vector<int> input;
extern std::vector<int> output;
extern std::vector<int (*)(int)> functions;
void test()
{
for (auto values : zip(input, functions, output))
{
auto &in = std::get<0>(values);
auto &func = std::get<1>(values);
auto &out = std::get<2>(values);
out = func(in); // error, i is not declared
// won't compile:
// i = func(in);
}
}
对于zip迭代器,关于何时一个迭代器设置&#39;一直是一个哲学问题。是平等的#39;到另一个。当其中一个迭代器对相等(在最短序列结束时停止)或它们全部相等(要求所有序列长度相同)时应该是吗?
在这个实现中,我使用了前者 - 当覆盖最短序列时停止迭代。您可以通过修改iterators<>
。
这是完整的例子,包括管道:
#include <vector>
#include <utility>
#include <tuple>
template<class...Iters>
struct iterators
{
iterators(Iters... iters) : _iterators { iters... } {}
bool operator==(const iterators& r) const {
return !(_iterators != r._iterators);
}
bool operator!=(const iterators& r) const {
return _iterators != r._iterators;
}
template<std::size_t...Is>
auto refs(std::index_sequence<Is...>)
{
return std::tie(*std::get<Is>(_iterators)...);
}
auto operator*() {
return refs(std::index_sequence_for<Iters...>());
}
template<std::size_t...Is>
auto& plus(std::size_t n, std::index_sequence<Is...>)
{
using expand = int[];
void(expand{0,
((std::get<Is>(_iterators) += n),0)...
});
return *this;
}
auto& operator+=(std::size_t n) {
return plus(n, std::index_sequence_for<Iters...>());
}
auto& operator++() {
return operator+=(1);
}
std::tuple<Iters...> _iterators;
};
template<class...Ranges>
auto begins(Ranges&...ranges)
{
using iters_type = iterators<decltype(std::begin(ranges))...>;
return iters_type(std::begin(ranges)...);
}
template<class...Ranges>
auto ends(Ranges&...ranges)
{
using iters_type = iterators<decltype(std::begin(ranges))...>;
return iters_type(std::end(ranges)...);
}
template<class...Ranges>
struct ranges
{
ranges(Ranges&...rs)
: _ranges(rs...)
{}
template<std::size_t...Is>
auto make_begins(std::index_sequence<Is...>)
{
return begins(std::get<Is>(_ranges)...);
}
template<std::size_t...Is>
auto make_ends(std::index_sequence<Is...>)
{
return ends(std::get<Is>(_ranges)...);
}
auto begin() {
return make_begins(std::index_sequence_for<Ranges...>());
}
auto end() {
return make_ends(std::index_sequence_for<Ranges...>());
}
std::tuple<Ranges&...> _ranges;
};
template<class...Ranges>
auto zip(Ranges&...rs) {
return ranges<Ranges...>(rs...);
}
extern std::vector<int> input;
extern std::vector<int> output;
extern std::vector<int (*)(int)> functions;
void test()
{
for (auto values : zip(input, functions, output))
{
auto &in = std::get<0>(values);
auto &func = std::get<1>(values);
auto &out = std::get<2>(values);
out = func(in); // error, i is not declared
// won't compile:
// i = func(in);
}
}
哇,所有代码......必须有一些处理开销...
如果您启用优化(gcc 5.3 with -O2),则不会显示:
test():
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbp
pushq %rbx
subq $8, %rsp
movq output+8(%rip), %r15
movq functions+8(%rip), %r14
movq input+8(%rip), %r13
movq input(%rip), %rbx
movq functions(%rip), %rbp
movq output(%rip), %r12
jmp .L4
.L2:
movl (%rbx), %edi
addq $4, %r12
addq $4, %rbx
call *0(%rbp)
addq $8, %rbp
movl %eax, -4(%r12)
.L4:
cmpq %rbx, %r13
jne .L2
cmpq %rbp, %r14
jne .L2
cmpq %r12, %r15
jne .L2
addq $8, %rsp
popq %rbx
popq %rbp
popq %r12
popq %r13
popq %r14
popq %r15
ret