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                       ]