Reputation: 51
I'm trying to create a function that will return pair containing two data types, where first type is always the same, but second is template-type. Is that even possible? (I'm also wondering if my understanding of std::forward
usage is correct). For better demonstrating of my problem I'll show you simplified sample of my (not working) code.
Here's what I tried:
template <class X>
std::pair<int, X> func(X&& second)
{
int first = 1;
return std::make_pair(std::move(first), std::forward<X>(second));
}
Inside function, I create variable first
and then I want to return pair. Here I move first
- to avoid copying - and (following Scott Meyers' lecture where he explained std::forward
as an "conditional move") depending if parameter second
was l-value I want to pass second
as an l-value (to let std::make_pair
make copy of second
, when creating pair) or if it was r-value I want to pass "moved" r-value.
Unfortunately my code doesn't work. I think I must have misunderstood something, but I don't know what, can you explain me, please?
Upvotes: 1
Views: 2184
Reputation: 50540
I suspect you want a C++14-ish std::decay_t
or a std::remove_reference_t
in your declaration:
template <class X>
std::pair<int, std::decay_t<X>> func(X&& second) {
int first = 1;
return std::make_pair(std::move(first), std::forward<X>(second));
}
Or the C++11, more verbose, but equivalent version:
template <class X>
std::pair<int, typename std::decay<X>::type> func(X&& second) {
int first = 1;
return std::make_pair(std::move(first), std::forward<X>(second));
}
This way, no matter if you are using an lvalue reference or an rvalue reference to X
as an actual parameter of func
, your std::pair
will use X
as a type.
Note that you can't use a reference to X
as a type of a std::pair
.
Let's consider the following example:
#include<utility>
template <class X>
std::pair<int, X> func(X&& second) {
int first = 1;
return std::make_pair(std::move(first), std::forward<X>(second));
}
int main() {
int i = 42;
func(i);
}
In this case, X
is deduced as int &
. Return type is thus std::pair<int, int &>
, that is not allowed and doesn't compile.
The following will compile instead:
template <class X>
std::pair<int, std::remove_reference_t<X>> func(X&& second) {
int first = 1;
return std::make_pair(std::move(first), std::forward<X>(second));
}
This is because X
is still deduced as int &
, but the return type is now adjusted to std::pair<int, int>
.
Upvotes: 4