I have something like (let's say):
template <typename Collection, typename Item>
void foo_collection(Collection&& c, Item && i) {
foo(std::forward<Collection>(c), std::forward<Item>(i));
}
I don't like the fact that std::forward<Collection>(c)
is so long. I'd like to do this, instead:
template <typename Collection, typename Item>
void foo_collection(Collection&& c, Item&& i) {
foo(FWD(c), FWD(i));
}
I am thinking there must be a way to do this using decltype
. I figure, given the decltype(i)
, if I remove all references and consts from it, I'll get Item
, and then it should work:
#define FWD(v) \
std::forward< \
typename std::remove_const<\
typename std::remove_reference<\
decltype(v)>::type>::type>(v)
However, this doesn't work:
void foo(int& a) { cout << "ref" << endl; }
void foo(const int& a) { cout << "cref" << endl; }
template <typename T>
void call_foo(T&& t) { foo(FWD(t)); }
int main() {
int a = 10;
foo(10); // 1) prints cref
foo(a); // 2) prints ref
call_foo(10); // 3) prints cref
call_foo(a); // 4) prints cref
return 0;
}
Why does 4
call the cref
overload, and not the ref
overload?
I tried #define FWD(a) std::forward<decltype(a)>(a)
, and in this example it did work. However, I am guessing that it won't work in all cases. Is that the case, and if so, which cases won't it work in?
Finally, if the latter approach doesn't work, is there any way to write this macro in a way that works?
#define FWD(a) std::forward<decltype(a)>(a)
will work. So long as a
is the name of a variable, decltype(a)
is the type it was declared as, which is what you are supposed to pass to forward
as its type parameter.
If you pass in an expression, things could get strange. I cannot think up a case where it fails, however.
Naturally this doesn't work for some more advanced uses of forward
.