How can I write a function template that returns either a reference or a value?
up vote
11
down vote
favorite
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
add a comment |
up vote
11
down vote
favorite
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
add a comment |
up vote
11
down vote
favorite
up vote
11
down vote
favorite
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
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
c++ templates c++17
edited Nov 19 at 17:03
asked Jun 7 at 3:32
Peter Ruderman
10k2252
10k2252
add a comment |
add a comment |
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
Works like a charm. Thank you, kindly.
– Peter Ruderman
Jun 7 at 3:55
add a comment |
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...
I did make an attempt to usestd::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 wheredecltype(auto)
is by no doubt the best solution.
– Daniel Langr
Jun 7 at 15:57
add a comment |
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
Works like a charm. Thank you, kindly.
– Peter Ruderman
Jun 7 at 3:55
add a comment |
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
Works like a charm. Thank you, kindly.
– Peter Ruderman
Jun 7 at 3:55
add a comment |
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
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
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
add a comment |
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
add a comment |
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...
I did make an attempt to usestd::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 wheredecltype(auto)
is by no doubt the best solution.
– Daniel Langr
Jun 7 at 15:57
add a comment |
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...
I did make an attempt to usestd::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 wheredecltype(auto)
is by no doubt the best solution.
– Daniel Langr
Jun 7 at 15:57
add a comment |
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...
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...
answered Jun 7 at 15:14
Daniel Langr
6,3262246
6,3262246
I did make an attempt to usestd::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 wheredecltype(auto)
is by no doubt the best solution.
– Daniel Langr
Jun 7 at 15:57
add a comment |
I did make an attempt to usestd::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 wheredecltype(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
add a comment |
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%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
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