patterncppCritical
Is it possible to declare two variables of different types in a for loop?
Viewed 0 times
variablespossibletwodeclarefortypesloopdifferent
Problem
Is it possible to declare two variables of different types in the initialization body of a for loop in C++?
For example:
defines two integers. Can I define an
For example:
for(int i=0,j=0 ...defines two integers. Can I define an
int and a char in the initialization body? How would this be done?Solution
C++17: Yes! You should use a structured binding declaration. The syntax has been supported in gcc and clang since gcc-7 and clang-4.0 (clang live example). This allows us to unpack a tuple like so:
The above will give you:
Make sure to
You can specify the exact types inside the
A specific application of this is iterating over a map, getting the key and value,
See a live example here
C++14: You can do the same as C++11 (below) with the addition of type-based
C++11:
For more than two objects, you'll need to use a
Within the for loop bodies you can easily alias the objects, though you still need to use
C++98 and C++03 You can explicitly name the types of a
for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
// ...
}The above will give you:
int iset to1
double fset to1.0
std::string sset to"ab"
Make sure to
#include for this kind of declaration.You can specify the exact types inside the
tuple by typing them all out as I have with the std::string, if you want to name a type. For example:auto [vec, i32] = std::tuple{std::vector{3, 4, 5}, std::int32_t{12}}A specific application of this is iterating over a map, getting the key and value,
std::unordered_map m = { /*...*/ };
for (auto& [key, value] : m) {
// ...
}See a live example here
C++14: You can do the same as C++11 (below) with the addition of type-based
std::get. So instead of std::get(t) in the below example, you can have std::get(t).C++11:
std::make_pair allows you to do this, as well as std::make_tuple for more than two objects.for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}std::make_pair will return the two arguments in a std::pair. The elements can be accessed with .first and .second.For more than two objects, you'll need to use a
std::tuplefor (auto t = std::make_tuple(0, std::string("Hello world"), std::vector{});
std::get(t) (t)) {
std::cout (t) (t).push_back(std::get(t)); // add counter value to the vector
}std::make_tuple is a variadic template that will construct a tuple of any number of arguments (with some technical limitations of course). The elements can be accessed by index with std::get(tuple_object)Within the for loop bodies you can easily alias the objects, though you still need to use
.first or std::get for the for loop condition and update expressionfor (auto t = std::make_tuple(0, std::string("Hello world"), std::vector{});
std::get(t) (t)) {
auto& i = std::get(t);
auto& s = std::get(t);
auto& v = std::get(t);
std::cout << s << '\n'; // cout Hello world
v.push_back(i); // add counter value to the vector
}C++98 and C++03 You can explicitly name the types of a
std::pair. There is no standard way to generalize this to more than two types though:for (std::pair p(5, "Hello World"); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}Code Snippets
for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
// ...
}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) {
// ...
}for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
std::cout << p.second << '\n';
}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
}Context
Stack Overflow Q#2687392, score: 257
Revisions (0)
No revisions yet.