Topic: rvalues and template argument deduction
Author: "Bart Samwel" <bsamwel@gmail.com>
Date: Mon, 25 Apr 2005 10:18:40 CST Raw View
NOTE: This posting is the result of a discussion on comp.lang.c++,
subject "Template argument deduction on integer literals".
Please consider this snippet:
template<typename A>
void foo(A&)
{
}
int main()
{
foo(10);
}
What happens here is that the type deduced for A is "int", after which
compilation fails because one cannot bind an rvalue to a reference that
is not to "const". This happens with all compilers that I've tried
(Comeau, g++ 3.3, MSVC++ 7.1). However, IMHO the compiler *should* be
able to see that the value passed is an rvalue, and it *should* know
that if it selects "int" here, that compilation will subsequently fail.
Quoting the standard [temp.deduct.call], the compiler can apply the
following alternative deduction:
"If the original P is a reference type, the deduced A (i.e., the type
referred to by the reference) can be more cv-qualified than A."
In the snippet above, as I read the standard, P = "int&", so the
deduced "A" is allowed to be "int" but also "const int". However, the
standard also says here that:
"These alternatives are considered only if type deduction would
otherwise fail."
So, apparently type deduction doesn't fail in the situation in the
snippet above. But the subsequent call *always* fails, and this should
be perfectly clear to the compiler! So, my question is, might it be a
good idea to change the standard to include the rvalue-ness of the
passed value in the equation, and to always deduce a top-level "const"
qualifier whenever the value whose type is "A" is an rvalue and "P" is
a reference type?
--Bart
P.S.: For those of you who want to know why I would want this to work
this way, please read the discussion in comp.lang.c++. I explain the
situation I'm dealing with in some length there.
The abstract: I'm trying to build a "generic pass-through" function
which passes on its arguments to another, unknown function (in this
case, a constructor for a type which is also a template parameter), and
which passes the arguments through completely unchanged, so that the
same function overload is selected as when the function would have been
called directly, preserving both reference-ness and constness for all
arguments. We provide overloads for 0 to 20 arguments for the
pass-through function, so providing overloads for all combinations of
const/non-const argument types is not an option; this would yield 2**20
overloads for the 20-argument version alone!
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Howard Hinnant <hinnant@metrowerks.com>
Date: Mon, 25 Apr 2005 10:59:20 CST Raw View
In article <1114339382.885440.25740@z14g2000cwz.googlegroups.com>,
"Bart Samwel" <bsamwel@gmail.com> wrote:
> The abstract: I'm trying to build a "generic pass-through" function
> which passes on its arguments to another, unknown function (in this
> case, a constructor for a type which is also a template parameter), and
> which passes the arguments through completely unchanged, so that the
> same function overload is selected as when the function would have been
> called directly, preserving both reference-ness and constness for all
> arguments. We provide overloads for 0 to 20 arguments for the
> pass-through function, so providing overloads for all combinations of
> const/non-const argument types is not an option; this would yield 2**20
> overloads for the 20-argument version alone!
You are in good company. The "forwarding problem" has a good survey
here:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
The "perfect forwarding" solution (#7 in the above link) is working its
way through the committee now. Here is the proposed wording:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html
which is under review by the Core Working Group.
Anticipated syntax is:
template<typename T, typename T1, typename T2, typename T3>
void my_new(T1&& a1, T2&& a2, T3&& a3)
{
/* ... */
new T(std::forward<T1>(a1),
std::forward<T2>(a2),
std::forward<T3>(a3));
/* ... */
}
You will be able to call my_new with both cv-qualified lvalues and
rvalues (i.e. one overload fits all 3 parameter cases).
The "&&" is used for "rvalue reference" here instead of changing the
meaning of "&" (current or lvalue reference) in order to avoid backwards
compatibility problems and to preserve the current functionality of
unintended binding to rvalues.
A separate proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1704.pdf
is exploring the possibility of a language change that would allow a
single template function to simultaneously handle the 0 thru N parameter
case where N is arbitrarily large.
-Howard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]