This page states the following:
Given that we have the following factory template function:
template<typename T, typename Arg>
shared_ptr<T> factory(Arg&& arg)
{
return shared_ptr<T>(new T(forward<Arg>(arg)));
}
One can choose among any of the two forward implementations:
- forward implementation using remove_reference
template<class S>
S&& forward(typename remove_reference<S>::type& a) noexcept
{
return static_cast<S&&>(a);
}
- forward implementation without remove_reference
template<class S>
S&& forward(S& a) noexcept
{
return static_cast<S&&>(a);
}
In the tutorial, it's mentioned that:
If you want to dig a little deeper for extra credit, ask yourself this question: why is the remove_reference in the definition of std::forward needed? The answer is, it is not really needed at all. If you use just S& instead of remove_reference::type& in the defintion of std::forward, you can repeat the case distinction above to convince yourself that perfect forwarding still works just fine. However, it works fine only as long as we explicitly specify Arg as the template argument of std::forward. The purpose of the remove_reference in the definition of std::forward is to force us to do so.
Why does using remove_reference forces us to specify Arg as the template arg, are there any concrete examples where the difference is illustrated? The code appears to be the same since in both instances of forward, the type is derived from the template argument. I am also new to c so sorry if i am missing something obvious here.
CodePudding user response:
Why does using remove_reference forces us to specify Arg as the template arg
Because having a nested type remove_reference<S>::type
as an argument makes a non-deducible context.
This applies for any nested type. For example, if you have
template< class T>
struct Identity
{
using type = T;
};
template< class T> void foo(T&){}
template< class T> void bar(typename Identity<T>::type&){}
then
int x;
foo(x);
bar<int>(x);
will compile, but
int x;
bar(x);
will not.