Name alias references for pair or tuple values
When restructuring some code I came across a 'problem' when returning a struct with 2 values. Now these really should be named for the documented effect. Later on I wanted to use tie
so i changed the struct into inheriting from std::pair
and just setting references. Now this actually works fine, but you will notice now my struct has the size of 24 as opposed to just 8 compared to the pair.
#include <tuple>
struct Transaction : public std::pair<int, int> {
using pair::pair;
int& deducted = first;
int& transfered = second;
};
//static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));//commenting in this line will fail compilation
Transaction makeTheTransaction();
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
The maybe obvious method is to change into member functions, however that is also too much 'boilerplate' for this case (then it just becomes easier not use tie
later on). A direct memcpy is to eg. a tuple is straigt forward UB. A direct structured binding is also not doable since the variables is already in use.
My question is what is a better or minimal code solution disregarding reusable parts (and given that the size shouldn't grow beyond the size of 2 ints) ?
UPDATE: For this case I ended up just doing a plain struct and hold return in a temporary. For other users coming here, there is a library proposal to boost that seems to be able to convert any struct to tuple: https://github.com/apolukhin/magic_get/
c++ c++17 std-pair stdtuple structured-bindings
|
show 1 more comment
When restructuring some code I came across a 'problem' when returning a struct with 2 values. Now these really should be named for the documented effect. Later on I wanted to use tie
so i changed the struct into inheriting from std::pair
and just setting references. Now this actually works fine, but you will notice now my struct has the size of 24 as opposed to just 8 compared to the pair.
#include <tuple>
struct Transaction : public std::pair<int, int> {
using pair::pair;
int& deducted = first;
int& transfered = second;
};
//static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));//commenting in this line will fail compilation
Transaction makeTheTransaction();
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
The maybe obvious method is to change into member functions, however that is also too much 'boilerplate' for this case (then it just becomes easier not use tie
later on). A direct memcpy is to eg. a tuple is straigt forward UB. A direct structured binding is also not doable since the variables is already in use.
My question is what is a better or minimal code solution disregarding reusable parts (and given that the size shouldn't grow beyond the size of 2 ints) ?
UPDATE: For this case I ended up just doing a plain struct and hold return in a temporary. For other users coming here, there is a library proposal to boost that seems to be able to convert any struct to tuple: https://github.com/apolukhin/magic_get/
c++ c++17 std-pair stdtuple structured-bindings
2
Simply:struct Transaction {int deducted; int transfered; };
?
– Jarod42
Nov 20 '18 at 19:26
@Jarod42 that would fine, but it would fail to document whatmakeTheTransaction()
returns.
– darune
Nov 20 '18 at 19:26
Why do you have to inherit from std::pair at all? You could just have makeTransaction return a plain-old pair, seeing as you don't appear to use the "deducted" and "transferred" fields (which wouldn't work as written, the references would need to be set in a constructor).
– jwimberley
Nov 20 '18 at 19:38
1
Inheriting std::pair is UB.
– felix
Nov 20 '18 at 19:40
I don't understand why you need to inherit fromstd::pair
in order to usestd::tie
. Just use it:auto t = std::tie(transaction.deducted, transaction.transferred)
.
– Peter Ruderman
Nov 20 '18 at 19:41
|
show 1 more comment
When restructuring some code I came across a 'problem' when returning a struct with 2 values. Now these really should be named for the documented effect. Later on I wanted to use tie
so i changed the struct into inheriting from std::pair
and just setting references. Now this actually works fine, but you will notice now my struct has the size of 24 as opposed to just 8 compared to the pair.
#include <tuple>
struct Transaction : public std::pair<int, int> {
using pair::pair;
int& deducted = first;
int& transfered = second;
};
//static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));//commenting in this line will fail compilation
Transaction makeTheTransaction();
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
The maybe obvious method is to change into member functions, however that is also too much 'boilerplate' for this case (then it just becomes easier not use tie
later on). A direct memcpy is to eg. a tuple is straigt forward UB. A direct structured binding is also not doable since the variables is already in use.
My question is what is a better or minimal code solution disregarding reusable parts (and given that the size shouldn't grow beyond the size of 2 ints) ?
UPDATE: For this case I ended up just doing a plain struct and hold return in a temporary. For other users coming here, there is a library proposal to boost that seems to be able to convert any struct to tuple: https://github.com/apolukhin/magic_get/
c++ c++17 std-pair stdtuple structured-bindings
When restructuring some code I came across a 'problem' when returning a struct with 2 values. Now these really should be named for the documented effect. Later on I wanted to use tie
so i changed the struct into inheriting from std::pair
and just setting references. Now this actually works fine, but you will notice now my struct has the size of 24 as opposed to just 8 compared to the pair.
#include <tuple>
struct Transaction : public std::pair<int, int> {
using pair::pair;
int& deducted = first;
int& transfered = second;
};
//static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));//commenting in this line will fail compilation
Transaction makeTheTransaction();
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
The maybe obvious method is to change into member functions, however that is also too much 'boilerplate' for this case (then it just becomes easier not use tie
later on). A direct memcpy is to eg. a tuple is straigt forward UB. A direct structured binding is also not doable since the variables is already in use.
My question is what is a better or minimal code solution disregarding reusable parts (and given that the size shouldn't grow beyond the size of 2 ints) ?
UPDATE: For this case I ended up just doing a plain struct and hold return in a temporary. For other users coming here, there is a library proposal to boost that seems to be able to convert any struct to tuple: https://github.com/apolukhin/magic_get/
c++ c++17 std-pair stdtuple structured-bindings
c++ c++17 std-pair stdtuple structured-bindings
edited Nov 21 '18 at 13:34
darune
asked Nov 20 '18 at 19:19
darunedarune
1,462516
1,462516
2
Simply:struct Transaction {int deducted; int transfered; };
?
– Jarod42
Nov 20 '18 at 19:26
@Jarod42 that would fine, but it would fail to document whatmakeTheTransaction()
returns.
– darune
Nov 20 '18 at 19:26
Why do you have to inherit from std::pair at all? You could just have makeTransaction return a plain-old pair, seeing as you don't appear to use the "deducted" and "transferred" fields (which wouldn't work as written, the references would need to be set in a constructor).
– jwimberley
Nov 20 '18 at 19:38
1
Inheriting std::pair is UB.
– felix
Nov 20 '18 at 19:40
I don't understand why you need to inherit fromstd::pair
in order to usestd::tie
. Just use it:auto t = std::tie(transaction.deducted, transaction.transferred)
.
– Peter Ruderman
Nov 20 '18 at 19:41
|
show 1 more comment
2
Simply:struct Transaction {int deducted; int transfered; };
?
– Jarod42
Nov 20 '18 at 19:26
@Jarod42 that would fine, but it would fail to document whatmakeTheTransaction()
returns.
– darune
Nov 20 '18 at 19:26
Why do you have to inherit from std::pair at all? You could just have makeTransaction return a plain-old pair, seeing as you don't appear to use the "deducted" and "transferred" fields (which wouldn't work as written, the references would need to be set in a constructor).
– jwimberley
Nov 20 '18 at 19:38
1
Inheriting std::pair is UB.
– felix
Nov 20 '18 at 19:40
I don't understand why you need to inherit fromstd::pair
in order to usestd::tie
. Just use it:auto t = std::tie(transaction.deducted, transaction.transferred)
.
– Peter Ruderman
Nov 20 '18 at 19:41
2
2
Simply:
struct Transaction {int deducted; int transfered; };
?– Jarod42
Nov 20 '18 at 19:26
Simply:
struct Transaction {int deducted; int transfered; };
?– Jarod42
Nov 20 '18 at 19:26
@Jarod42 that would fine, but it would fail to document what
makeTheTransaction()
returns.– darune
Nov 20 '18 at 19:26
@Jarod42 that would fine, but it would fail to document what
makeTheTransaction()
returns.– darune
Nov 20 '18 at 19:26
Why do you have to inherit from std::pair at all? You could just have makeTransaction return a plain-old pair, seeing as you don't appear to use the "deducted" and "transferred" fields (which wouldn't work as written, the references would need to be set in a constructor).
– jwimberley
Nov 20 '18 at 19:38
Why do you have to inherit from std::pair at all? You could just have makeTransaction return a plain-old pair, seeing as you don't appear to use the "deducted" and "transferred" fields (which wouldn't work as written, the references would need to be set in a constructor).
– jwimberley
Nov 20 '18 at 19:38
1
1
Inheriting std::pair is UB.
– felix
Nov 20 '18 at 19:40
Inheriting std::pair is UB.
– felix
Nov 20 '18 at 19:40
I don't understand why you need to inherit from
std::pair
in order to use std::tie
. Just use it: auto t = std::tie(transaction.deducted, transaction.transferred)
.– Peter Ruderman
Nov 20 '18 at 19:41
I don't understand why you need to inherit from
std::pair
in order to use std::tie
. Just use it: auto t = std::tie(transaction.deducted, transaction.transferred)
.– Peter Ruderman
Nov 20 '18 at 19:41
|
show 1 more comment
3 Answers
3
active
oldest
votes
It seems like you're over-complicating the problem to me. If you need to use std::tie
, you can just use it. There's no need to alter your structure:
struct Transaction
{
int deducted;
int transferred;
};
// later...
auto t = std::tie(transaction.deducted, transaction.transferred);
If this is a pattern you use frequently, then you can wrap it in a little helper method:
struct Transaction
{
int deducted;
int transferred;
auto to_tuple() const
{
return std::tie(deducted, transferred);
}
};
You can also use this to assign to multiple variables at once, although I strongly discourage that. It's error prone and leads to brittle code. (For example, if you reverse the order of deduct
and transfer
in the example below, you've got a bug, but the compiler will give no warning or error.)
void test(int& deduct, int& transfer)
{
std::tie(deduct, transfer) = makeTheTransaction().to_tuple();
}
Edit: On second thought...
If the goal here is just easy decomposition of the struct into variables, you could do that directly and avoid using pairs or tuples:
struct Transaction
{
int deducted;
int transferred;
void decompose(int* deducted_, int* transferred_)
{
*deducted_ = deducted;
*transferred_ = transferred;
}
};
void test(int& deduct, int& transfer)
{
makeTheTransaction().decompose(&deduct, &transfer);
}
This is still brittle, but at least now you'll get intellisense when you write the call to the decompose
method, which will make the pattern a little less error prone.
The member functionto_tuple
can work.
– darune
Nov 20 '18 at 20:06
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
1
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
add a comment |
I would simply go with:
struct Transaction
{
int deducted;
int transfered;
};
With usage similar to:
Transaction makeTheTransaction() { return {4, 2}; }
int main()
{
auto [deduct, transfer] = makeTheTransaction();
std::cout << deduct << transfer << std::endl;
}
Demo
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
add a comment |
Adding a conversion function works:
#include <tuple>
struct Transaction {
std::pair<int, int> data_;
operator std::tuple<int &, int &> () {
return std::tie(data_.first, data_.second);
}
};
static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));
Transaction makeTheTransaction() {
return Transaction();
}
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
I don't think that this will cause any lifetime issue when using with std::tie.
This Transaction
doesn't work with structured binding with two identifiers. But you can make it supports "tuple-like" binding by specializing std::get
and std::tuple_size
for it.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400051%2fname-alias-references-for-pair-or-tuple-values%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
It seems like you're over-complicating the problem to me. If you need to use std::tie
, you can just use it. There's no need to alter your structure:
struct Transaction
{
int deducted;
int transferred;
};
// later...
auto t = std::tie(transaction.deducted, transaction.transferred);
If this is a pattern you use frequently, then you can wrap it in a little helper method:
struct Transaction
{
int deducted;
int transferred;
auto to_tuple() const
{
return std::tie(deducted, transferred);
}
};
You can also use this to assign to multiple variables at once, although I strongly discourage that. It's error prone and leads to brittle code. (For example, if you reverse the order of deduct
and transfer
in the example below, you've got a bug, but the compiler will give no warning or error.)
void test(int& deduct, int& transfer)
{
std::tie(deduct, transfer) = makeTheTransaction().to_tuple();
}
Edit: On second thought...
If the goal here is just easy decomposition of the struct into variables, you could do that directly and avoid using pairs or tuples:
struct Transaction
{
int deducted;
int transferred;
void decompose(int* deducted_, int* transferred_)
{
*deducted_ = deducted;
*transferred_ = transferred;
}
};
void test(int& deduct, int& transfer)
{
makeTheTransaction().decompose(&deduct, &transfer);
}
This is still brittle, but at least now you'll get intellisense when you write the call to the decompose
method, which will make the pattern a little less error prone.
The member functionto_tuple
can work.
– darune
Nov 20 '18 at 20:06
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
1
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
add a comment |
It seems like you're over-complicating the problem to me. If you need to use std::tie
, you can just use it. There's no need to alter your structure:
struct Transaction
{
int deducted;
int transferred;
};
// later...
auto t = std::tie(transaction.deducted, transaction.transferred);
If this is a pattern you use frequently, then you can wrap it in a little helper method:
struct Transaction
{
int deducted;
int transferred;
auto to_tuple() const
{
return std::tie(deducted, transferred);
}
};
You can also use this to assign to multiple variables at once, although I strongly discourage that. It's error prone and leads to brittle code. (For example, if you reverse the order of deduct
and transfer
in the example below, you've got a bug, but the compiler will give no warning or error.)
void test(int& deduct, int& transfer)
{
std::tie(deduct, transfer) = makeTheTransaction().to_tuple();
}
Edit: On second thought...
If the goal here is just easy decomposition of the struct into variables, you could do that directly and avoid using pairs or tuples:
struct Transaction
{
int deducted;
int transferred;
void decompose(int* deducted_, int* transferred_)
{
*deducted_ = deducted;
*transferred_ = transferred;
}
};
void test(int& deduct, int& transfer)
{
makeTheTransaction().decompose(&deduct, &transfer);
}
This is still brittle, but at least now you'll get intellisense when you write the call to the decompose
method, which will make the pattern a little less error prone.
The member functionto_tuple
can work.
– darune
Nov 20 '18 at 20:06
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
1
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
add a comment |
It seems like you're over-complicating the problem to me. If you need to use std::tie
, you can just use it. There's no need to alter your structure:
struct Transaction
{
int deducted;
int transferred;
};
// later...
auto t = std::tie(transaction.deducted, transaction.transferred);
If this is a pattern you use frequently, then you can wrap it in a little helper method:
struct Transaction
{
int deducted;
int transferred;
auto to_tuple() const
{
return std::tie(deducted, transferred);
}
};
You can also use this to assign to multiple variables at once, although I strongly discourage that. It's error prone and leads to brittle code. (For example, if you reverse the order of deduct
and transfer
in the example below, you've got a bug, but the compiler will give no warning or error.)
void test(int& deduct, int& transfer)
{
std::tie(deduct, transfer) = makeTheTransaction().to_tuple();
}
Edit: On second thought...
If the goal here is just easy decomposition of the struct into variables, you could do that directly and avoid using pairs or tuples:
struct Transaction
{
int deducted;
int transferred;
void decompose(int* deducted_, int* transferred_)
{
*deducted_ = deducted;
*transferred_ = transferred;
}
};
void test(int& deduct, int& transfer)
{
makeTheTransaction().decompose(&deduct, &transfer);
}
This is still brittle, but at least now you'll get intellisense when you write the call to the decompose
method, which will make the pattern a little less error prone.
It seems like you're over-complicating the problem to me. If you need to use std::tie
, you can just use it. There's no need to alter your structure:
struct Transaction
{
int deducted;
int transferred;
};
// later...
auto t = std::tie(transaction.deducted, transaction.transferred);
If this is a pattern you use frequently, then you can wrap it in a little helper method:
struct Transaction
{
int deducted;
int transferred;
auto to_tuple() const
{
return std::tie(deducted, transferred);
}
};
You can also use this to assign to multiple variables at once, although I strongly discourage that. It's error prone and leads to brittle code. (For example, if you reverse the order of deduct
and transfer
in the example below, you've got a bug, but the compiler will give no warning or error.)
void test(int& deduct, int& transfer)
{
std::tie(deduct, transfer) = makeTheTransaction().to_tuple();
}
Edit: On second thought...
If the goal here is just easy decomposition of the struct into variables, you could do that directly and avoid using pairs or tuples:
struct Transaction
{
int deducted;
int transferred;
void decompose(int* deducted_, int* transferred_)
{
*deducted_ = deducted;
*transferred_ = transferred;
}
};
void test(int& deduct, int& transfer)
{
makeTheTransaction().decompose(&deduct, &transfer);
}
This is still brittle, but at least now you'll get intellisense when you write the call to the decompose
method, which will make the pattern a little less error prone.
edited Nov 20 '18 at 20:26
answered Nov 20 '18 at 19:46
Peter RudermanPeter Ruderman
10.2k2352
10.2k2352
The member functionto_tuple
can work.
– darune
Nov 20 '18 at 20:06
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
1
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
add a comment |
The member functionto_tuple
can work.
– darune
Nov 20 '18 at 20:06
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
1
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
The member function
to_tuple
can work.– darune
Nov 20 '18 at 20:06
The member function
to_tuple
can work.– darune
Nov 20 '18 at 20:06
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
Your first suggestion with plain struct is also 'painfull'. While maybe not brittle as you say, it leads to overly complicated code. The thing is, first I have to create and name a temporary variable to hold the returned struct. Then I have to assign to the other 2 variables - now 3 lines of code. Then, in order to not polute the rest of the scope with the temporary, i have to put a block scope around those 3 lines.
– darune
Nov 21 '18 at 13:07
1
1
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
Well, I'd suggest two things. First, typing is not the bottleneck. Saving yourself a few lines a typing is rarely worth opening up the possibility of future bugs. We should strive for code that is correct by construction. Second, passing the entire struct around seems like the easier option. Why is it necessary to decompose the struct into multiple variables?
– Peter Ruderman
Nov 21 '18 at 13:12
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
I aggree with the passing around is better done with the struct. However, I find, it's sometimes the case when dealing with existing (legacy) code and restructuring it that you only want to take one or a few steps at a time for different reasons (eg. one reason is not knowing the size of surrounding code that needs to be updated - another is not loosing your focus too much). I now ended up just doing the plain struct and returning into a temporary (for now). Thanks for the feedback.
– darune
Nov 21 '18 at 13:31
add a comment |
I would simply go with:
struct Transaction
{
int deducted;
int transfered;
};
With usage similar to:
Transaction makeTheTransaction() { return {4, 2}; }
int main()
{
auto [deduct, transfer] = makeTheTransaction();
std::cout << deduct << transfer << std::endl;
}
Demo
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
add a comment |
I would simply go with:
struct Transaction
{
int deducted;
int transfered;
};
With usage similar to:
Transaction makeTheTransaction() { return {4, 2}; }
int main()
{
auto [deduct, transfer] = makeTheTransaction();
std::cout << deduct << transfer << std::endl;
}
Demo
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
add a comment |
I would simply go with:
struct Transaction
{
int deducted;
int transfered;
};
With usage similar to:
Transaction makeTheTransaction() { return {4, 2}; }
int main()
{
auto [deduct, transfer] = makeTheTransaction();
std::cout << deduct << transfer << std::endl;
}
Demo
I would simply go with:
struct Transaction
{
int deducted;
int transfered;
};
With usage similar to:
Transaction makeTheTransaction() { return {4, 2}; }
int main()
{
auto [deduct, transfer] = makeTheTransaction();
std::cout << deduct << transfer << std::endl;
}
Demo
answered Nov 20 '18 at 19:29
Jarod42Jarod42
117k12103186
117k12103186
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
add a comment |
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
Suggest that it's C++17 specific?
– jwimberley
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
It has to work with previous declared variables. I somehow forgot that in the question..
– darune
Nov 20 '18 at 19:30
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
I updated the example code to show that with test function doing return by parameter
– darune
Nov 20 '18 at 19:33
add a comment |
Adding a conversion function works:
#include <tuple>
struct Transaction {
std::pair<int, int> data_;
operator std::tuple<int &, int &> () {
return std::tie(data_.first, data_.second);
}
};
static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));
Transaction makeTheTransaction() {
return Transaction();
}
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
I don't think that this will cause any lifetime issue when using with std::tie.
This Transaction
doesn't work with structured binding with two identifiers. But you can make it supports "tuple-like" binding by specializing std::get
and std::tuple_size
for it.
add a comment |
Adding a conversion function works:
#include <tuple>
struct Transaction {
std::pair<int, int> data_;
operator std::tuple<int &, int &> () {
return std::tie(data_.first, data_.second);
}
};
static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));
Transaction makeTheTransaction() {
return Transaction();
}
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
I don't think that this will cause any lifetime issue when using with std::tie.
This Transaction
doesn't work with structured binding with two identifiers. But you can make it supports "tuple-like" binding by specializing std::get
and std::tuple_size
for it.
add a comment |
Adding a conversion function works:
#include <tuple>
struct Transaction {
std::pair<int, int> data_;
operator std::tuple<int &, int &> () {
return std::tie(data_.first, data_.second);
}
};
static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));
Transaction makeTheTransaction() {
return Transaction();
}
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
I don't think that this will cause any lifetime issue when using with std::tie.
This Transaction
doesn't work with structured binding with two identifiers. But you can make it supports "tuple-like" binding by specializing std::get
and std::tuple_size
for it.
Adding a conversion function works:
#include <tuple>
struct Transaction {
std::pair<int, int> data_;
operator std::tuple<int &, int &> () {
return std::tie(data_.first, data_.second);
}
};
static_assert(sizeof(Transaction) == sizeof(std::pair<int, int>));
Transaction makeTheTransaction() {
return Transaction();
}
void test(int& deduct, int& transfer) {
std::tie(deduct, transfer) = makeTheTransaction();
}
I don't think that this will cause any lifetime issue when using with std::tie.
This Transaction
doesn't work with structured binding with two identifiers. But you can make it supports "tuple-like" binding by specializing std::get
and std::tuple_size
for it.
edited Nov 20 '18 at 19:56
answered Nov 20 '18 at 19:47
felixfelix
1,510314
1,510314
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53400051%2fname-alias-references-for-pair-or-tuple-values%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
Simply:
struct Transaction {int deducted; int transfered; };
?– Jarod42
Nov 20 '18 at 19:26
@Jarod42 that would fine, but it would fail to document what
makeTheTransaction()
returns.– darune
Nov 20 '18 at 19:26
Why do you have to inherit from std::pair at all? You could just have makeTransaction return a plain-old pair, seeing as you don't appear to use the "deducted" and "transferred" fields (which wouldn't work as written, the references would need to be set in a constructor).
– jwimberley
Nov 20 '18 at 19:38
1
Inheriting std::pair is UB.
– felix
Nov 20 '18 at 19:40
I don't understand why you need to inherit from
std::pair
in order to usestd::tie
. Just use it:auto t = std::tie(transaction.deducted, transaction.transferred)
.– Peter Ruderman
Nov 20 '18 at 19:41