Need Help: Tuple - element access
Hi guys,
In my ongoing quest to learn (slowly) C++, I've now come across Tuples.
There is something about accessing the elements using std::get which I can't wrap my head around.
Here's my test code:
Code:
#include <iostream>
#include <vector>
#include <tuple>
using namespace std;
int funcInitialize ();
int funcPrintData ();
typedef tuple <string, string, int> tupData;
vector <tupData> tupEmployees;
int main()
{
funcInitialize ();
funcPrintData ();
return 0;
}
// Functions //
int funcInitialize ()
{
tupEmployees.push_back(tupData("Smith", "John", 22));
tupEmployees.push_back(tupData("Jones", "Jack", 24));
tupEmployees.push_back(tupData("Smith", "Jane", 23));
return 0;
}
int funcPrintData ()
{
// Print all elements //
for (unsigned int row = 0; row < tupEmployees.size(); row++)
{
cout << get<0>(tupEmployees[row]) << ", ";
cout << get<1>(tupEmployees[row]) << " ";
cout << get<2>(tupEmployees[row]) << endl;
}
cout << endl << endl;
// Print single element //
int row = 1;
const int col = 0;
cout << get<col>(tupEmployees[row]) << " " << endl;
cout << endl << endl;
return 0;
}
Result:
Code:
Smith, John 22
Jones, Jack 24
Smith, Jane 23
Jones
Now, while the result is as expected, I can't figure out how to get around the limitation of the template parameter (in my example the const int col) having to be a compile-time const value. Is there a work-around for this using pointers or references, so that the value in/of col can be incremented? All my attempts have failed (not surprising!).
As always, any help would be appreciated. Thanks in advance.
Re: Need Help: Tuple - element access
You can use tie to unpack a tuple object. See http://www.cplusplus.com/reference/tuple/tie/
eg
Code:
#include <iostream>
#include <vector>
#include <tuple>
#include <string>
using namespace std;
int funcInitialize();
int funcPrintData();
typedef tuple <string, string, int> tupData;
vector <tupData> tupEmployees;
int main()
{
funcInitialize();
funcPrintData();
return 0;
}
int funcInitialize()
{
tupEmployees.push_back(tupData("Smith", "John", 22));
tupEmployees.push_back(tupData("Jones", "Jack", 24));
tupEmployees.push_back(tupData("Smith", "Jane", 23));
return 0;
}
int funcPrintData()
{
for (const auto& tu : tupEmployees)
{
string na1, na2;
int nu;
tie(na1, na2, nu) = tu;
cout << na1 << ", " << na2 << " " << nu << endl;
}
cout << endl << endl;
return 0;
}
Re: Need Help: Tuple - element access
Thanks, 2kaud.
Although I looked at that page for std::tie, it just didn't "click" to me as a solution.
Just two questions.
1. What exactly is going on here:
Code:
for (const auto& tu : tupEmployees)
or, what is the equivalent of that in a "normal" for-loop?
2. What would be the equivalent for accessing a single element like this:
Code:
int row = 1;
const int col = 0;
cout << get<col>(tupEmployees[row]) << " " << endl;
and, how would one change the values directly in the tuple (tupEmployees) with your solution as compared to this:
Code:
int na1 = 0;
get<0>(tupEmployees[na1]) = "Jones";
Thanks.
Re: Need Help: Tuple - element access
Quote:
what is the equivalent of that in a "normal" for-loop?
That is a 'normal' c++11 for loop for iterating through the elements of a container :D. See http://www.learncpp.com/cpp-tutorial...static_assert/
Quote:
What would be the equivalent for accessing a single element like this:
c++ is a typed language and all types must be resolved at compile time. As a tuple can have 'columns' of different types, access by 'column' number must be resolved at compile time so that the type of the result is known at compile time. However, consider
Code:
#include <iostream>
#include <vector>
#include <tuple>
#include <string>
using namespace std;
int funcInitialize();
int funcPrintData();
enum cols {name1 = 0, name2, age};
typedef tuple <string, string, int> tupData;
const auto nocols = tuple_size<tupData>::value;
vector <tupData> tupEmployees;
void show(size_t col)
{
if (col >= nocols)
{
cout << "bad column value: " << col << endl;
return;
}
for (const auto& tu : tupEmployees)
{
switch (col) {
case name1:
cout << get<name1>(tu) << endl;
break;
case name2:
cout << get<name2>(tu) << endl;
break;
case age:
cout << get<age>(tu) << endl;
break;
}
}
}
int main()
{
funcInitialize();
funcPrintData();
return 0;
}
int funcInitialize()
{
tupEmployees.push_back(tupData("Smith", "John", 22));
tupEmployees.push_back(tupData("Jones", "Jack", 24));
tupEmployees.push_back(tupData("Smith", "Jane", 23));
return 0;
}
int funcPrintData()
{
show(3); //This will show error message
for (size_t c = 0; c < nocols; ++c) {
cout << "col " << c << endl;
show(c);
cout << endl;
}
return 0;
}
show() takes a variable as the column number to display.
Re: Need Help: Tuple - element access
Ah, ok, I see.
Using switch/case is a simple work-around for 'compile-time const value requirement'. That makes sense.
Thanks again for your help with all my questions, 2kaud.
Re: Need Help: Tuple - element access
Quote:
Originally Posted by
Marc63
Using switch/case is a simple work-around for 'compile-time const value requirement'. That makes sense.
Instead of using a switch to map columns to actions you can use an std::array (or std::vector) for the same purpose. At each index position the array holds a lambda expression corresponding to a switch selection for a certain column.
This is not necessarily better but it's a first step toward more general code and it's more dynamic because the array (or vector) can be assigned new lambdas at runtime and it can even be expected to be faster (in principle). It also has more of a C++ 11 feel to it. :)
Code:
#include <tuple>
#include <string>
#include <functional>
#include <array>
#include <vector>
typedef std::tuple <std::string, std::string, int> tupData;
std::vector <tupData> tupEmployees;
void test() {
tupEmployees.push_back(tupData("Smith", "John", 22));
tupEmployees.push_back(tupData("Jones", "Jack", 24));
tupEmployees.push_back(tupData("Smith", "Jane", 23));
// column lambdas
auto doCol0 = [&](int row) {std::cout << std::get<0>(tupEmployees[row]) << ", ";};
auto doCol1 = [&](int row) {std::cout << std::get<1>(tupEmployees[row]) << " ";};
auto doCol2 = [&](int row) {std::cout << std::get<2>(tupEmployees[row]) << std::endl;};
// assign lambdas to action array
std::array<std::function<void(int)>, std::tuple_size<tupData>::value> tupAction = {
doCol0, doCol1, doCol2
};
// std::vector<std::function<void(int)>> tupAction = {doCol0, doCol1, doCol2}; // vector works too
for (int row=0; row<int(tupEmployees.size()); ++row) { // for all rows
for (int col=0; col<int(tupAction.size()); ++col) { // for all columns
tupAction[col](row); // do something
}
}
}