The rule in [over.match.class.deduct] is:
A set of functions and function templates is formed comprising:
- For each constructor of the primary class template designated by the template-name, if the template is defined, a function template with the following properties:
- The template parameters are the template parameters of the class template followed by the template parameters (including default template arguments) of the constructor, if any.
- The types of the function parameters are those of the constructor.
- The return type is the class template specialization designated by the template-name and template arguments corresponding to the template parameters obtained from the class template.
Our set includes:
template <class T> // <-- the template parameters come from the class template
S<T> // <-- the return type is the class template specialization
foo(T&& ); // <-- the types of the parameters are those of the constructor
We perform overload resolution as usual, which involves template deduction. But from [temp.deduct.call]:
A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])). If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.
Hence, this T&&
is not a forwarding reference. It is an rvalue reference to T
. So deduction against an lvalue (in our case, S(i)
) fails. gcc is correct to reject your code here.
If you want the class template parameter to function as a forwarding reference, you will need to add a deduction guide:
template <class T> S(T&& ) -> S<T>;