是否有可能在for循环中声明两个不同类型的变量?

是否有可能在c++的for循环的初始化体中声明两个不同类型的变量?

例如:

for(int i=0,j=0 ...

定义两个整数。我可以在初始化体中定义intchar吗?如何做到这一点呢?

238915 次浏览

不可能,但你可以:

float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}

或者,使用额外的括号显式限制fi的范围:

{
float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
//...
}
}

你不能在初始化时声明多个类型,但是你可以赋值给多个类型

{
int i;
char x;
for(i = 0, x = 'p'; ...){
...
}
}

只是在它们自己的范围内声明它们。

没有-但技术上有一个变通的方法(不是说我真的会使用它,除非被迫):

for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a)
{
std::cout << s.a << " " << s.b << std::endl;
}

有关嵌套多个for循环的另一种方法,请参阅“是否有一种方法来定义两种类型的变量在循环?”。与Georg的“结构技巧”相比,另一种方法的优势在于:(1)允许你混合使用静态和非静态局部变量;(2)允许你使用不可复制的变量。缺点是可读性差得多,效率也可能较低。

定义一个宏:

#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循环中。

你应该使用结构化绑定声明。gcc和clang从gcc-7和clang-4.0 (当啷现场例子)开始支持该语法。这允许我们像这样解包元组:

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>

你可以在tuple中指定确切的类型,就像我在std::string中那样,如果你想命名一个类型。例如:

auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}

它的一个具体应用是遍历一个map,获取键和值,

std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
// ...
}

参见一个生动的例子在这里


c++ 14:你可以像c++ 11(如下)一样,添加基于类型的std::get。所以你可以用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循环条件和更新表达式使用.firststd::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';
}

我认为最好的方法是西安的回答

但是…


#嵌套for循环

这种方法很脏,但可以解决所有版本。

所以,我经常在宏函数中使用它。

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
}

额外的1。

它也可以用于declare local variablesinitialize global variables

float globalFloat;


for(int localInt=0, /* decalre local variable */ \
_=1;_;_=0)


for(globalFloat=2.f; localInt<3; localInt++) /* initialize global variable */
{
// do.
}

额外的2。

很好的例子:使用宏函数。

(如果最好的方法不能使用,因为它是for-loop-宏)

#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语句技巧

if (A* a=nullptr);
else
for(...) // a is visible

如果你想初始化为0nullptr,你可以使用这个技巧。

但我不建议这样做,因为很难阅读。

它看起来像虫子。

你也可以像下面这样在c++中使用。

int j=3;
int i=2;
for (; i<n && j<n ; j=j+2, i=i+2){
// your code
}