#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;
// The forward_as template
template<typename T, typename U>
auto forward_as( U&& u ) -> typename std::conditional<
std::is_reference<T>::value,
typename std::remove_reference<U>::type&,
typename std::remove_reference<U>::type&&>::type
{
return static_cast<decltype(forward_as<T, U>(u))>(u);
}
// Structs for testing
struct X {};
struct Y {
vector<X> range;
Y() : range(1) {}
};
// bar will tell us the actual reference type of the forwarding reference
struct Bar {
void operator()(X&& t) { cout << "t is a r-value reference\n"; }
void operator()(X& t) { cout << "t is an l-value reference\n"; }
void operator()(const X& t) { cout << "t is passed by const reference\n"; }
} bar;
// Elementwise perfect forwarding of a member range
template<typename T>
void foo( T&& t ) {
for (auto& r : t.range)
bar(forward_as<T>(r));
}
// Elementwise perfect forwarding of a member range
template<typename T>
void algo_foo( T&& t ) {
std::for_each(std::begin(std::forward<T>(t).range), std::end(std::forward<T>(t).range), bar);
}
// Naive and non-working attempt
template<typename T>
void naive_foo( T&& t ) {
for (auto&& r : forward<T>(t).range)
bar(r);
}
int main() {
// Pass by r-value reference.
cout << "foo(Y()):\n\t";
foo(Y());
cout << "naive_foo(Y()):\n\t";
naive_foo(Y());
cout << "algo_foo(Y()):\n\t";
algo_foo(Y());
// Pass by l-value reference.
Y y;
cout << "foo(y):\n\t";
foo(y);
cout << "naive_foo(y):\n\t";
naive_foo(y);
cout << "algo_foo(y):\n\t";
algo_foo(y);
}