在 C++ 的 for 循环初始化体中,能否声明两个不同类型的变量?
例如:
for(int i=0,j=0 ...
定义了两个整数。我能在初始化主体中定义一个int
和char
吗?如何做到呢?
在 C++ 的 for 循环初始化体中,能否声明两个不同类型的变量?
例如:
for(int i=0,j=0 ...
定义了两个整数。我能在初始化主体中定义一个int
和char
吗?如何做到呢?
不行 - 但技术上有一个变通方法(除非被迫,否则我实际上不会使用它):
for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a)
{
std::cout << s.a << " " << s.b << std::endl;
}
struct { int a=0; char b='a'; } s;
。 - Ryan Hainingfor(struct { std::vector<float>::iterator it; size_t count; } v { vec.begin(), 1 }; v.it < vec.end(); ++v.it, ++v.count) { ... }
- adfriedman不能实现,但您可以这样做:
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
或者,使用额外的括号明确限定f
和i
的作用域:
{
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
}
C++17: 是的! 你应该使用结构化绑定声明。自gcc-7和clang-4.0以来,这种语法已经得到了支持(clang实时示例)。这使我们可以像这样解包元组:
for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
// ...
}
int i
被设置为 1
double f
被设置为 1.0
std::string s
被设置为 "ab"
#include <tuple>
。std::string
那样在tuple
中指定所有类型。例如:auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}
std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
// ...
}
点击此处查看实时示例。
C++14: 你可以通过类型为基础的std::get
来实现与C++11(下面)相同的功能。因此,在下面的示例中,可以使用std::get<int>(t)
代替std::get<0>(t)
。
C++11: std::make_pair
可以让您做到这一点,而std::make_tuple
可以用于两个以上对象。
for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}
std::make_pair
函数会返回一个由两个参数组成的 std::pair
对象。可以使用 .first
和 .second
访问这两个元素。
当有超过两个对象时,需要使用 std::tuple
。
for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
std::cout << std::get<1>(t) << '\n'; // cout Hello world
std::get<2>(t).push_back(std::get<0>(t)); // add counter value to the vector
}
std::make_tuple
是一个可变参模板,可以构造任意数量的参数元组(当然有一些技术上的限制)。元素可以通过索引使用std::get<INDEX>(tuple_object)
进行访问。
在for循环体中,您可以轻松地给对象起别名,但在for循环条件和更新表达式中仍需要使用.first
或std::get
。
for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
std::get<0>(t) < 10;
++std::get<0>(t)) {
auto& i = std::get<0>(t);
auto& s = std::get<1>(t);
auto& v = std::get<2>(t);
std::cout << s << '\n'; // cout Hello world
v.push_back(i); // add counter value to the vector
}
C++98和C++03,您可以显式命名std::pair
的类型。但是,没有标准的方法可以将其推广到超过两个类型:
for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}
make_
并直接写成std::pair(1, 1.0)
。 - Marc Glissestd
命名空间以自命不凡的姿态存在于语言中,这只是朝着错误方向迈出的一大步,在我看来跨越了太远的距离。 - Armen Michaeli你无法在初始化时声明多个类型,但是可以将值分配给多个类型,例如:
{
int i;
char x;
for(i = 0, x = 'p'; ...){
...
}
}
在它们自己的作用域中声明它们即可。
但是...
这种方法虽然有点糟糕,但可以解决所有版本的问题。
所以,在宏函数中我经常使用它。
for(int _int=0, /* make local variable */ \
loopOnce=true; loopOnce==true; loopOnce=false)
for(char _char=0; _char<3; _char++)
{
// do anything with
// _int, _char
}
它还可以用于声明局部变量
和初始化全局变量
。
float globalFloat;
for(int localInt=0, /* decalre local variable */ \
_=1;_;_=0)
for(globalFloat=2.f; localInt<3; localInt++) /* initialize global variable */
{
// do.
}
好的例子:使用宏函数。
(如果因为使用了for-loop-macro而无法使用最佳方法,那么请参考此示例)
#define for_two_decl(_decl_1, _decl_2, cond, incr) \
for(_decl_1, _=1;_;_=0)\
for(_decl_2; (cond); (incr))
for_two_decl(int i=0, char c=0, i<3, i++)
{
// your body with
// i, c
}
if (A* a=nullptr);
else
for(...) // a is visible
0
或nullptr
,可以使用这个技巧。
但是我不建议这样做,因为它很难阅读。
而且看起来像一个错误。
for(int i = 0; i < whatever; i++) if (A & a = get_a(i))
,它不会破坏break
和continue
,并且是透明的。缺点是A必须实现一个显式的operator bool返回true。 - xryl669if
语句技巧,谢谢。 - Sam Liddicott在C++中,你也可以像下面这样使用。
int j=3;
int i=2;
for (; i<n && j<n ; j=j+2, i=i+2){
// your code
}
定义一个宏:
#define FOR( typeX,x,valueX, typeY,y,valueY, condition, increments) typeX x; typeY y; for(x=valueX,y=valueY;condition;increments)
FOR(int,i,0, int,f,0.0, i < 5, i++)
{
//...
}
请记住,这种方式下你的变量作用域也不会在for循环内部。
{
和 }
将宏中的代码包装在单独的作用域中来轻松克服这个限制。 - Nathan Osman
-std=c++0x
)дёӯпјҢеҸҜд»ҘдҪҝз”Ёfor(auto i=0, j=0.0; ...
зҡ„еҪўејҸпјҢдҪҶжҳҜеңЁg++-4.5дёӯиҝҷз§ҚеҸҜиғҪжҖ§иў«з§»йҷӨд»ҘдёҺc++0xж–Үжң¬дёҖиҮҙгҖӮ - rafak