Topic: Proposal re function template argument deduction


Author: John Wiegley <jwiegley@inprise.com>
Date: Mon, 19 Feb 2001 21:20:45 GMT
Raw View
>>>>> On Mon Feb  5, Anthony writes:

> If the argument is of type T&, and the supplied argument is an
> rvalue of type U, then deduce T to be const U.

It sounds like the real question here is: What is the type of '3'?

The compiler is making it 'int'.  Fair enough.  If we muck with
template deduction, it would mean that if we change the template back
into a non-template, the call would suddenly be illegal.  It's rather
unintuitive for a template function to be callable, when its signature
would obviously forbid such a call if it were a non-template.  Again,
this is assuming that 3 is int.

Making literal 3 be 'const int' is more interesting, and would solve
your problem.  In fact, since 3 can't be bound to "int&", I wonder why
it isn't const int, and why your example doesn't already work.

---
[ 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.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Wed, 7 Feb 2001 17:09:15 GMT
Raw View
"Ron Natalie" <ron@spamcop.net> wrote in message
news:3A801B22.C0ED852@spamcop.net...
> [Trying again, the moderator queue seems to have discarded my initial copy
of this]
>
> Anthony Williams wrote:
>
> >
> > I propose that the argument deduction rules are changed, so this
situation
> > works, as follows:
> >
> > If the argument is of type T&, and the supplied argument is an rvalue of
> > type U, then deduce T to be const U.
> >
>
> I find that problematic.  Just because a type is an rvalue doesn't
> make it const.  Specifically, non-const behavior is frequently used
> with rvalues of class type.

But you can't bind a non-const reference to an rvalue. This is explicitly
for a case where the function argument is a reference to a template
parameter. If the actual supplied argument is an rvalue, then the only
reference that will bind is a const reference, so we need to deduce the
template parameter to be const.

void func(int& a);

func(int()); // cannot bind non-const ref to temporary
func(3); // cannot bind non-const ref to literal

in fact, in both cases, Comeau C++ complains about the lack of an lvalue.

void func(const int& a);

is the required signature.

Now we have a template

template<typename T> void func2(T&a);

func2(int());
func2(3);

Both of these work if T is deduced to be "const int", but not if T="int".

This will not affect normal deduction:

template<typename T> void func3(T a); // note no &

func3(int());
func3(3);

in both cases T=int.

> Furthermore, my assertion is your template is defective anyhow.  If you
> are prepared to accept const arguments, you probably ought to declare
> the template as expecting a const type:
>         template<class T> void func(const T&) { ...

The point is that the template doesn't know what arguments the target
function takes. In this case, its purpose is solely to forward the arguments
unchanged. The user of the template writes the target function (in my
example it was a constructor of a UDT), and specifies what arguments it
takes. The template function preserves its arguments and their types, and
passes it on. e.g.

class X;
void func(X& a);
void func(const X& a);

template<typename T> void func2(T&a)
{
   func(a);
}
template<typename T> void func3(T a)
{
  func(a);
}

func(X()); // calls func(const X&)
func2(X()); // refuses to bind, no lvalue for reference type
func3(X()); // binds T=X, calls func(const X&) with a copy of the temporary

X someX;

func(someX); // calls func(X&)
func2(someX); // binds T=X, calls func(X&)
func3(someX); // binds T=X, calls func(const X&) with a copy of someX

My proposal is to let func2(X()) work, and call func(const X&), by deducing
T to be const X.

func3 does not preserve the type of the argument, and copies the argument in
all cases. If X was an auto_ptr, then func3(someX) would kill someX, whereas
func(someX) would take it as a reference parameter, and only change it if
the author of func() decided to.

> Nothing is gained by leaving off the const (you either are going to do
> non-const operations to the type or not).
> If you wanted to pursue this, the fix is not to mess around with template
> deduction, the fault is not there.  The fix is to make literals (and
perhaps
> other temporaries of non-class type) to have "const" type.

My idea is to preserve as close as possible the type of the supplied
arguments, so that they can be passed on to other functions as-is. Changing
literals to be const is a good start, but not sufficiently wide ranging.

Anthony
--
Anthony Williams
Software Engineer, Nortel Networks
The opinions expressed in this message are mine and do not represent those
of my employer



---
[ 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.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Mon, 5 Feb 2001 14:19:43 GMT
Raw View
The following code doesn't work
template<typename T1>
void func(T1& a1)
{
}
int main()
{
    func(3);
}

because the constant integer expression "3" is an rvalue of type int, and
the deduced argument would be T=int => argument = int&, which won't bind to
the rvalue.

I propose that the argument deduction rules are changed, so this situation
works, as follows:

If the argument is of type T&, and the supplied argument is an rvalue of
type U, then deduce T to be const U.

This would allow temporaries to bind too.

The reason behind this code is that I am trying to write a template function
that forwards its arguments:

template<typename T,typename T1,typename T2>
T* create(T1& a1,T2& a2)
{
    return new T(1,a1,a2);
}

Thus create<T>(a,b) is the same as new T(1,a,b). If I omit the & in the
arguments, then things are passed by value, which may not be possible
(copy-constructor may not be accessible). If I leave them in, then literals
and temporaries don't work as arguments unless I overload the function with
const arguments:

template<typename T,typename T1,typename T2>
T* create(const T1& a1,T2& a2)
{
    return new T(1,a1,a2);
}
template<typename T,typename T1,typename T2>
T* create(T1& a1,const T2& a2)
{
    return new T(1,a1,a2);
}
template<typename T,typename T1,typename T2>
T* create(const T1& a1,const T2& a2)
{
    return new T(1,a1,a2);
}

Obviously, when I extend this to more than 2 arguments, the number of
overloads becomes unmanageable. My proposal would simplify the code, but
where the overloads were written, they would still be valid and chosen in
preference to the deduced versions, allowing the user to code different
variants if desired.

Anthony
--
Anthony Williams
Software Engineer, Nortel Networks
The opinions expressed in this message are mine and do not represent those
of my employer





---
[ 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.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: viisi@chello.at (Andreas Riedl)
Date: Mon, 5 Feb 2001 22:01:42 GMT
Raw View
>template<typename T,typename T1,typename T2>
>T* create(const T1& a1,const T2& a2)
>{
>    return new T(1,a1,a2);
>}
why would'nt this variant alone be sufficient
for your purpose?

cu, andi

---
[ 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.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Tue, 6 Feb 2001 11:14:22 GMT
Raw View
"Andreas Riedl" <viisi@chello.at> wrote in message
news:slrn97tl9f.492.viisi@elcher.stranitzky.org...
> >template<typename T,typename T1,typename T2>
> >T* create(const T1& a1,const T2& a2)
> >{
> >    return new T(1,a1,a2);
> >}
> why would'nt this variant alone be sufficient
> for your purpose?
>

What if the T constructor (or whatever function is forwarded to) expects
non-const arguments?

Anthony
--
Anthony Williams
Software Engineer, Nortel Networks
The opinions expressed in this message are mine and do not represent those
of my employer



---
[ 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.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]