Topic: template argument deduction


Author: Ralf Stoffels <stoffels@faho.rwth-aachen.de>
Date: 1999/03/12
Raw View
Is this function declaration legal ?

template <class T>
void f(typename A<T>::type x);

If it is legal, how shall the compiler deduce the template argument ?


Ralf
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1999/03/12
Raw View
Ralf Stoffels wrote:
>
> Is this function declaration legal ?
>
> template <class T>
> void f(typename A<T>::type x);
>
> If it is legal, how shall the compiler deduce the template argument ?

In general, it can't. Take a simple cases:

 template<class T> class A
 {
 public:
  T t;
  typedef int type;
 };

 int i=3;

 f(i);

How could it deduce whether to call f<int>(i) or f<double>(i) or
f<char>(i), etc.? You'd always have to use explicit template arguments
whenever you used this function.

Now, if A<T>::type were typedef'd as 'T', then it would be logically
possible to deduce the template argument from the function argument's
type. However, I'm not sure whether the standard requires an
implementation to do so.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/03/12
Raw View
On 12 Mar 99 03:06:06 GMT, Ralf Stoffels <stoffels@faho.rwth-aachen.de> wrote:

>Is this function declaration legal ?
>
>template <class T>
>void f(typename A<T>::type x);
>
>If it is legal, how shall the compiler deduce the template argument ?

I think the above is legal.  Given the expression
   f(3);
the compiler must look at all classes A<T> that
   [X] define the field A<T>::type
   [X] A<T>::type is a typedef or nested class
   [X] A<T>::type is int
Furthermore, there should only be one T for which A<T>::type is int.

Examples:

   template <class T> struct A { typedef T type; };
   template <> struct A<int> { };
   int main() { f(3); } // error: no T

   template <class T> struct A { typedef T type; };
   template <> struct A<int> { static const int type=1; };
   int main() { f(3); } // error: no T

   template <class T> struct A { typedef T type; };
   int main() { f(3); } // ok: T==int

   template <class T> struct A { typedef T type; };
   template <> struct A<double> { typedef int type; };
   int main() { f(3); } // error: T==int or T==double

   template <class T> struct A { typedef int type; };
   int main() { f(3); } // error: T can be anything


Now let's look at two real compilers.  These are egcs and como.

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

#include <iostream.h>

template <class T> struct A { typedef T type; };

inline template <class T> void f(typename A<T>::type x)
{
   cout << "f(" << x << ")\n";
}

int main()
{
   f(3);
}

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

[sbnaran@localhost] [/tmp] >> g++ e.cc
e.cc: In function `int main()':
e.cc:12: no matching function for call to `f (int)'


[sbnaran@localhost] [/tmp] >> como e.cc
Comeau C/C++ 4.2.38 (Oct 13 1998 03:37:37)
Copyright 1988-1998 Comeau Computing, Edison Design Group, Inc.

"e.cc", line 12: error: no instance of function template "f" matches the
          argument list
            argument types are: (int)
     f(3);
     ^

1 error detected in the compilation of "e.cc".

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/03/13
Raw View
Ralf Stoffels wrote:
> Is this function declaration legal ?
> template <class T>
> void f(typename A<T>::type x);

Yes it is.

> If it is legal, how shall the compiler deduce the template argument ?

The compiler does not deduce the template argument in this case.
See 14.8.2.4 paragraph 4 of the Standard. Basically, the compiler
is not to deduce template arguments. You would call this function
specifying the template parameter explicitly:

 f<myClass>(myClass::type());
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: esap@cs.tut.fi (Pulkkinen Esa)
Date: 1996/08/27
Raw View
Thinking of STL's functions like make_pair,
I can see one problem: It's not easy to store a return value of
a template function into a temporary variable.

For example consider I'd like to build a structure representing
expressions using templates. The code could look something like
the following:

template <class T,class U>
expr<mul<T,U> > operator*(const expr<T>&, const expr<U> &);

template <class T,class U>
expr<sum<T,U> > operator+(const expr<T>&, const expr<U> &);

// ... (also similar functions to handle constants etc).
(These functions are very similar to STL's make_pair, except operator
overloading is used).

And now, when I try to use these, I can write the following:

template <class T> void print(const expr<T>&);

expr<int> i;
expr<int> j;

print(i*(j+i)*2); // This is fine.

// The following works, but it's unnecessarily verbose:
expr<mul<mul<int,sum<int,int> >,const int> e = i*(j+i)*2;
// ...
print(e);

That is, if I try to temporarily store the result of the expression, I get
into trouble, since I have to write the full type of the expression -
which soon becomes unmanageable for more complex expressions.

What I would like to write is:

expr e = i*(j+i)*2; // The template argument deduced from the initializer.
print(e);

And the compiler could deduce the template argument from the type of the
expression. Since this isn't (an instantiation of) a function template,
the function template argument deduction rules don't apply, and as far
as my reading of the DWP is correct, this isn't currently allowed.

Now, what I'm proposing is that ordinary function template deduction rules
could be used to deduce class template's template arguments that depend on
the constructor arguments in a declaration (or any initialization) that
has an initializer.

For example:

template <class T>
class X {
  X(const T& t);
  X(int,T,int);
};

X x = 10;  // x would be X<int>
X y(10,string(),20); // y would be X<string>
pair p(10,X(10,less<int>(),20)); // p is pair<int,X<less<int> > >

Also, I think the compiler _could_ deduce the following:
(even if vector<int>::iterator were a typedef for int*, as often is the case)

vector<int> v;
vector::iterator i = v.begin(); // i is vector<int>::iterator

So what do you think?
--
   Esa Pulkkinen                        | C++ programmers do it virtually
   E-Mail:  esap@cs.tut.fi              | everywhere with a class, resulting
   WWW   :  http://www.cs.tut.fi/~esap/ | in multiple inheritance.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: vandevod@cs.rpi.edu (David Vandevoorde)
Date: 1996/08/27
Raw View
>>>>> "PE" == Pulkkinen Esa <esap@cs.tut.fi> writes:
[...]
PE> For example consider I'd like to build a structure representing
PE> expressions using templates. The code could look something like
PE> the following:

(Self-Plug: ftp://ftp.cs.rpi.edu/~vandevod/Valarray contains all
 sorts of stuff based on these principles; in particular, a non-
 conforming but very efficient implementation of valarray.)

PE> template <class T,class U>
PE> expr<mul<T,U> > operator*(const expr<T>&, const expr<U> &);

PE> template <class T,class U>
PE> expr<sum<T,U> > operator+(const expr<T>&, const expr<U> &);

[...]
PE> // The following works, but it's unnecessarily verbose:
PE> expr<mul<mul<int,sum<int,int> >,const int> e = i*(j+i)*2;

[...]
PE> That is, if I try to temporarily store the result of the expression, I get
PE> into trouble, since I have to write the full type of the expression -
PE> which soon becomes unmanageable for more complex expressions.

PE> What I would like to write is:

PE> expr e = i*(j+i)*2; // The template argument deduced from the initializer.

[...]
PE> Now, what I'm proposing is that ordinary function template deduction rules
PE> could be used to deduce class template's template arguments that depend on
PE> the constructor arguments in a declaration (or any initialization) that
PE> has an initializer.

I have also often wished for such a feature. It's not going to be standard
before 2000 though...

PE> For example:

PE> template <class T>
PE> class X {
PE>   X(const T& t);
PE>   X(int,T,int);
PE> };

PE> X x = 10;  // x would be X<int>

The above would be quite hard (it requires a conversion). However, I
suspect that deduction of T == int would be feasible for `X x(10);'.

Now, what about `X x(10), y(10.0);' ?

PE> X y(10,string(),20); // y would be X<string>
PE> pair p(10,X(10,less<int>(),20)); // p is pair<int,X<less<int> > >

PE> Also, I think the compiler _could_ deduce the following:
PE> (even if vector<int>::iterator were a typedef for int*,
PE> as often is the case)

It's not just a matter of a compiler being able to do it: the
programmer should have not too many difficulties understanding
what is happening. (Also, a natural description of the deduction
rules should be possible.)

PE> vector<int> v;
PE> vector::iterator i = v.begin(); // i is vector<int>::iterator

PE> So what do you think?

I think it's a useful idea: I have encountered situation where I
wished this relatively frequently. We'll need at least some patience
to see this sort of feature materialize, however. Personally, I think
the required deductions should be relatively simple and close to those
for function template arguments.

 Daveed
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]