How can I write a function template that returns either a reference or a value?











up vote
11
down vote

favorite
2












I'd like to write a function template that returns either a reference or a value depending on some compile time expression. What I've tried so far is something like this:



template<typename T>
auto&& Func()
{
if constexpr (some_compile_time_expression)
{
return GetReferenceFromSomewhere();
}
else
{
return GetValueFromSomewhere();
}
}


This works fine for all types of references but doesn't work for values. For example, if GetValueFromSomewhere returns a Foo, then the compiler deduces the return type of Func as Foo&& and warns that I'm returning the address of a temporary.



Is there any way to make this work, or am I forced to tease the two branches apart somehow (through function overloads or some such)?










share|improve this question




























    up vote
    11
    down vote

    favorite
    2












    I'd like to write a function template that returns either a reference or a value depending on some compile time expression. What I've tried so far is something like this:



    template<typename T>
    auto&& Func()
    {
    if constexpr (some_compile_time_expression)
    {
    return GetReferenceFromSomewhere();
    }
    else
    {
    return GetValueFromSomewhere();
    }
    }


    This works fine for all types of references but doesn't work for values. For example, if GetValueFromSomewhere returns a Foo, then the compiler deduces the return type of Func as Foo&& and warns that I'm returning the address of a temporary.



    Is there any way to make this work, or am I forced to tease the two branches apart somehow (through function overloads or some such)?










    share|improve this question


























      up vote
      11
      down vote

      favorite
      2









      up vote
      11
      down vote

      favorite
      2






      2





      I'd like to write a function template that returns either a reference or a value depending on some compile time expression. What I've tried so far is something like this:



      template<typename T>
      auto&& Func()
      {
      if constexpr (some_compile_time_expression)
      {
      return GetReferenceFromSomewhere();
      }
      else
      {
      return GetValueFromSomewhere();
      }
      }


      This works fine for all types of references but doesn't work for values. For example, if GetValueFromSomewhere returns a Foo, then the compiler deduces the return type of Func as Foo&& and warns that I'm returning the address of a temporary.



      Is there any way to make this work, or am I forced to tease the two branches apart somehow (through function overloads or some such)?










      share|improve this question















      I'd like to write a function template that returns either a reference or a value depending on some compile time expression. What I've tried so far is something like this:



      template<typename T>
      auto&& Func()
      {
      if constexpr (some_compile_time_expression)
      {
      return GetReferenceFromSomewhere();
      }
      else
      {
      return GetValueFromSomewhere();
      }
      }


      This works fine for all types of references but doesn't work for values. For example, if GetValueFromSomewhere returns a Foo, then the compiler deduces the return type of Func as Foo&& and warns that I'm returning the address of a temporary.



      Is there any way to make this work, or am I forced to tease the two branches apart somehow (through function overloads or some such)?







      c++ templates c++17






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 at 17:03

























      asked Jun 7 at 3:32









      Peter Ruderman

      10k2252




      10k2252
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          15
          down vote



          accepted










          Use decltype(auto) for the return type placeholder, it will preserve the exact value category of the function you're calling in the return statement



          template<typename T>
          decltype(auto) Func()
          {
          if constexpr (some_compile_time_expression_dependent_on_T)
          {
          return GetReferenceFromSomewhere();
          }
          else
          {
          return GetValueFromSomewhere();
          }
          }


          Live demo






          share|improve this answer























          • Works like a charm. Thank you, kindly.
            – Peter Ruderman
            Jun 7 at 3:55


















          up vote
          3
          down vote













          Pretorian's answer is perfect, but you may also want to learn about std::conditional, which has broader usage. For example, consider a data_ member variable of type int and a member function, that returns data_ either by reference or by value depending on some compile-time condition:



          template <bool COND>
          std::conditional_t<COND, int&, int> data() { return data_; }


          This would not be achievable with decltype(auto). You can also use the same technique to pass arguments to functions by reference/value:



          template <bool COND>
          void f(std::conditional_t<COND, int&, int> param);


          Or, you can switch between copy/move constructors:



          class X {
          X(std::conditional_t<some_cond, const X&, X&&>) = default;
          X(std::conditional_t<some_cond, X&&, const X&>) = delete;
          ...
          };


          Etc...






          share|improve this answer





















          • I did make an attempt to use std::conditional. It was not pretty.
            – Peter Ruderman
            Jun 7 at 15:45










          • @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
            – Daniel Langr
            Jun 7 at 15:57











          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',
          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%2f50732531%2fhow-can-i-write-a-function-template-that-returns-either-a-reference-or-a-value%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          15
          down vote



          accepted










          Use decltype(auto) for the return type placeholder, it will preserve the exact value category of the function you're calling in the return statement



          template<typename T>
          decltype(auto) Func()
          {
          if constexpr (some_compile_time_expression_dependent_on_T)
          {
          return GetReferenceFromSomewhere();
          }
          else
          {
          return GetValueFromSomewhere();
          }
          }


          Live demo






          share|improve this answer























          • Works like a charm. Thank you, kindly.
            – Peter Ruderman
            Jun 7 at 3:55















          up vote
          15
          down vote



          accepted










          Use decltype(auto) for the return type placeholder, it will preserve the exact value category of the function you're calling in the return statement



          template<typename T>
          decltype(auto) Func()
          {
          if constexpr (some_compile_time_expression_dependent_on_T)
          {
          return GetReferenceFromSomewhere();
          }
          else
          {
          return GetValueFromSomewhere();
          }
          }


          Live demo






          share|improve this answer























          • Works like a charm. Thank you, kindly.
            – Peter Ruderman
            Jun 7 at 3:55













          up vote
          15
          down vote



          accepted







          up vote
          15
          down vote



          accepted






          Use decltype(auto) for the return type placeholder, it will preserve the exact value category of the function you're calling in the return statement



          template<typename T>
          decltype(auto) Func()
          {
          if constexpr (some_compile_time_expression_dependent_on_T)
          {
          return GetReferenceFromSomewhere();
          }
          else
          {
          return GetValueFromSomewhere();
          }
          }


          Live demo






          share|improve this answer














          Use decltype(auto) for the return type placeholder, it will preserve the exact value category of the function you're calling in the return statement



          template<typename T>
          decltype(auto) Func()
          {
          if constexpr (some_compile_time_expression_dependent_on_T)
          {
          return GetReferenceFromSomewhere();
          }
          else
          {
          return GetValueFromSomewhere();
          }
          }


          Live demo







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jun 7 at 3:55

























          answered Jun 7 at 3:49









          Praetorian

          86.7k10183268




          86.7k10183268












          • Works like a charm. Thank you, kindly.
            – Peter Ruderman
            Jun 7 at 3:55


















          • Works like a charm. Thank you, kindly.
            – Peter Ruderman
            Jun 7 at 3:55
















          Works like a charm. Thank you, kindly.
          – Peter Ruderman
          Jun 7 at 3:55




          Works like a charm. Thank you, kindly.
          – Peter Ruderman
          Jun 7 at 3:55












          up vote
          3
          down vote













          Pretorian's answer is perfect, but you may also want to learn about std::conditional, which has broader usage. For example, consider a data_ member variable of type int and a member function, that returns data_ either by reference or by value depending on some compile-time condition:



          template <bool COND>
          std::conditional_t<COND, int&, int> data() { return data_; }


          This would not be achievable with decltype(auto). You can also use the same technique to pass arguments to functions by reference/value:



          template <bool COND>
          void f(std::conditional_t<COND, int&, int> param);


          Or, you can switch between copy/move constructors:



          class X {
          X(std::conditional_t<some_cond, const X&, X&&>) = default;
          X(std::conditional_t<some_cond, X&&, const X&>) = delete;
          ...
          };


          Etc...






          share|improve this answer





















          • I did make an attempt to use std::conditional. It was not pretty.
            – Peter Ruderman
            Jun 7 at 15:45










          • @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
            – Daniel Langr
            Jun 7 at 15:57















          up vote
          3
          down vote













          Pretorian's answer is perfect, but you may also want to learn about std::conditional, which has broader usage. For example, consider a data_ member variable of type int and a member function, that returns data_ either by reference or by value depending on some compile-time condition:



          template <bool COND>
          std::conditional_t<COND, int&, int> data() { return data_; }


          This would not be achievable with decltype(auto). You can also use the same technique to pass arguments to functions by reference/value:



          template <bool COND>
          void f(std::conditional_t<COND, int&, int> param);


          Or, you can switch between copy/move constructors:



          class X {
          X(std::conditional_t<some_cond, const X&, X&&>) = default;
          X(std::conditional_t<some_cond, X&&, const X&>) = delete;
          ...
          };


          Etc...






          share|improve this answer





















          • I did make an attempt to use std::conditional. It was not pretty.
            – Peter Ruderman
            Jun 7 at 15:45










          • @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
            – Daniel Langr
            Jun 7 at 15:57













          up vote
          3
          down vote










          up vote
          3
          down vote









          Pretorian's answer is perfect, but you may also want to learn about std::conditional, which has broader usage. For example, consider a data_ member variable of type int and a member function, that returns data_ either by reference or by value depending on some compile-time condition:



          template <bool COND>
          std::conditional_t<COND, int&, int> data() { return data_; }


          This would not be achievable with decltype(auto). You can also use the same technique to pass arguments to functions by reference/value:



          template <bool COND>
          void f(std::conditional_t<COND, int&, int> param);


          Or, you can switch between copy/move constructors:



          class X {
          X(std::conditional_t<some_cond, const X&, X&&>) = default;
          X(std::conditional_t<some_cond, X&&, const X&>) = delete;
          ...
          };


          Etc...






          share|improve this answer












          Pretorian's answer is perfect, but you may also want to learn about std::conditional, which has broader usage. For example, consider a data_ member variable of type int and a member function, that returns data_ either by reference or by value depending on some compile-time condition:



          template <bool COND>
          std::conditional_t<COND, int&, int> data() { return data_; }


          This would not be achievable with decltype(auto). You can also use the same technique to pass arguments to functions by reference/value:



          template <bool COND>
          void f(std::conditional_t<COND, int&, int> param);


          Or, you can switch between copy/move constructors:



          class X {
          X(std::conditional_t<some_cond, const X&, X&&>) = default;
          X(std::conditional_t<some_cond, X&&, const X&>) = delete;
          ...
          };


          Etc...







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jun 7 at 15:14









          Daniel Langr

          6,3262246




          6,3262246












          • I did make an attempt to use std::conditional. It was not pretty.
            – Peter Ruderman
            Jun 7 at 15:45










          • @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
            – Daniel Langr
            Jun 7 at 15:57


















          • I did make an attempt to use std::conditional. It was not pretty.
            – Peter Ruderman
            Jun 7 at 15:45










          • @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
            – Daniel Langr
            Jun 7 at 15:57
















          I did make an attempt to use std::conditional. It was not pretty.
          – Peter Ruderman
          Jun 7 at 15:45




          I did make an attempt to use std::conditional. It was not pretty.
          – Peter Ruderman
          Jun 7 at 15:45












          @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
          – Daniel Langr
          Jun 7 at 15:57




          @PeterRuderman Your case is different, since the return type is determined by the return type of functions you invoke internally. That's where decltype(auto) is by no doubt the best solution.
          – Daniel Langr
          Jun 7 at 15:57


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f50732531%2fhow-can-i-write-a-function-template-that-returns-either-a-reference-or-a-value%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







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          TypeError: fit_transform() missing 1 required positional argument: 'X'