|
-
November 6th, 2015, 12:21 PM
#1
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.
-
November 6th, 2015, 12:49 PM
#2
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;
}
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
November 6th, 2015, 01:48 PM
#3
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.
-
November 6th, 2015, 04:45 PM
#4
Re: Need Help: Tuple - element access
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 . See http://www.learncpp.com/cpp-tutorial...static_assert/
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.
Last edited by 2kaud; November 6th, 2015 at 04:59 PM.
Reason: code change
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
November 7th, 2015, 10:22 AM
#5
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.
-
November 8th, 2015, 04:09 AM
#6
Re: Need Help: Tuple - element access
 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
}
}
}
Last edited by tiliavirga; November 8th, 2015 at 11:29 AM.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|