Name alias references for pair or tuple values












1















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/










share|improve this question




















  • 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 use std::tie. Just use it: auto t = std::tie(transaction.deducted, transaction.transferred).

    – Peter Ruderman
    Nov 20 '18 at 19:41


















1















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/










share|improve this question




















  • 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 use std::tie. Just use it: auto t = std::tie(transaction.deducted, transaction.transferred).

    – Peter Ruderman
    Nov 20 '18 at 19:41
















1












1








1








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/










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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 use std::tie. Just use it: auto t = std::tie(transaction.deducted, transaction.transferred).

    – Peter Ruderman
    Nov 20 '18 at 19:41
















  • 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 use std::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














3 Answers
3






active

oldest

votes


















1














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.






share|improve this answer


























  • 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






  • 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



















0














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






share|improve this answer
























  • 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



















0














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.






share|improve this answer

























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    1














    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.






    share|improve this answer


























    • 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






    • 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
















    1














    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.






    share|improve this answer


























    • 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






    • 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














    1












    1








    1







    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.






    share|improve this answer















    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 20 '18 at 20:26

























    answered Nov 20 '18 at 19:46









    Peter RudermanPeter Ruderman

    10.2k2352




    10.2k2352













    • 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






    • 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











    • 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













    0














    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






    share|improve this answer
























    • 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
















    0














    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






    share|improve this answer
























    • 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














    0












    0








    0







    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






    share|improve this answer













    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







    share|improve this answer












    share|improve this answer



    share|improve this answer










    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



















    • 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











    0














    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.






    share|improve this answer






























      0














      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.






      share|improve this answer




























        0












        0








        0







        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.






        share|improve this answer















        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.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 20 '18 at 19:56

























        answered Nov 20 '18 at 19:47









        felixfelix

        1,510314




        1,510314






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini