Topic: template functions intricacies


Author: int19h@gmail.com
Date: Tue, 3 Jul 2007 08:01:55 CST
Raw View
On 27 Jun, 02:40, "mikel...@gmail.com" <mikel...@gmail.com> wrote:

> I am trying to compile something like this:
>
> template <class T, class U>
> void g(typename foo<T>::val& a, typename foo<U>::val& b)
> {  std::cout << a.p<<","<<b.p<<"\n"; }
> g++ 4.1.2 complains with the error messages
>
> ################################
> tctc.cpp: In member function 'void foo<M>::h(foo<N>&) [with N = float,
> M = int]':
> tctc.cpp:37:   instantiated from here
> tctc.cpp:29: error: no matching function for call to
> 'g(foo<int>::val&, foo<float>::val&)'

The problem is that the Standard explicitly states that something like
"foo<T>::bar" is in a nondeduced context (meaning the compiler won't
even try to deduce the type of T if it's not explicitly specified)".
>From 14.8.2.4 [temp.deduct.type]:

"If a template parameter is used only in nondeduced contexts and is
not explicitly specified, template argument deduction fails. The
nondeduced contexts are:
- The nested-name-specifier of a type that was specified using a
qualified-id. ..."

In your case, "foo<T>::bar" is qualified-id, and "foo<T>" is a nested-
name-specifier, therefore T is undeducible.
The solution is to lift "val" into the surrounding namespace, so that
is is no longer a nested type in a template.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "mikelito@gmail.com" <mikelito@gmail.com>
Date: Tue, 26 Jun 2007 16:40:24 CST
Raw View
>>>SORRY, I PREVIOUSLY POSTED ONLY HALF OF THE MESSAGE! <<<<

hello. I hope someone of you c++ gurus can help me out of this.

I am trying to compile something like this:

*********************************************************
template <class M>
class foo {
public:
  class val {  public: M p; };
  val v;
  template <class N> void h(foo<N>& c);
};

template <class T, class U>
void g(typename foo<T>::val& a, typename foo<U>::val& b)
{  std::cout << a.p<<","<<b.p<<"\n"; }

template <class M>
template <class N> void foo<M>::h(foo<N>& c)
{  g((*this).v,c.v);  /*1*/}

int main(int argc, char*argv[])
{
  foo<int> i1,i2;
  foo<float> f1;
  i1.v.p=1;i2.v.p=2; f1.v.p=0.1;f2.v.p=0.2;
  i1.h(f1);
  i1.h(i2);
  f1.h(i2);
}
***********************************************************

g++ 4.1.2 complains with the error messages

################################
tctc.cpp: In member function 'void foo<M>::h(foo<N>&) [with N = float,
M = int]':
tctc.cpp:37:   instantiated from here
tctc.cpp:29: error: no matching function for call to
'g(foo<int>::val&, foo<float>::val&)'
tctc.cpp: In member function 'void foo<M>::h(foo<N>&) [with N = int, M
= int]':
tctc.cpp:38:   instantiated from here
tctc.cpp:29: error: no matching function for call to
'g(foo<int>::val&, foo<int>::val&)'
tctc.cpp: In member function 'void foo<M>::h(foo<N>&) [with N = int, M
= float]':
tctc.cpp:39:   instantiated from here
tctc.cpp:29: error: no matching function for call to
'g(foo<float>::val&, foo<int>::val&)'
#################################

if I change line /*1*/  making the template function call explicit
  g<M,N>((*this).v,c.v);
everything works fine. so
1)  I can't understand this behaviour
2) the problem is not solved by explicitly making the template call
explicit:
    2a) if I declare g (prepending
**
template <class M> class foo;
template <class T,class U> void g(typename foo<T>::val& a, typename
foo<U>::val& b);
**
           to the code above), the problem with the "implicit" call is
not solved, and even the explicit
           "solution" breaks, giving a _linker_ error
##
/tmp/ccsWnHwv.o: In function `void foo<int>::h<float>(foo<float>&)':
tctc.cpp:(.text._ZN3fooIiE1hIfEEvRS_IT_E[void
foo<int>::h<float>(foo<float>&)]+0x14): undefined reference to `void
g<int, float>(foo<int>::val&, foo<float>::val&)'
##
     2b) the explicit call would be a mess if I wanted to play with
overloading, i.e. defining also
*
 template <class T>
void g(typename foo<T>::val& a, typename foo<T>::val& b)
{  std::cout << a.p<<","<<b.p<<"\n"; }
*
          and assuming the compiler to choose properly when to use one
call [e.g. i1.h(f1) ]
          or the other [i1.h(i2)]


thank you!

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: =?iso-8859-1?q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Sun, 1 Jul 2007 21:59:45 CST
Raw View
On 27 Jun., 00:40, "mikel...@gmail.com" <mikel...@gmail.com> wrote:
[..]
> if I change line /*1*/  making the template function call explicit
>   g<M,N>((*this).v,c.v);
> everything works fine. so
> 1)  I can't understand this behaviour

The problem is, that the compiler cannot deduce the template
arguments T and U from a call to g without explicit specification
of the template argument types in this case.
The reason is, that in C++ you can simply specialize every template
in a more or less arbitrary manner. Someone could simply specialize
foo in the following way:

template <>
class foo<int> {
public:
  class val { public: double p; }; // Note: double, *not* int!
  // .. remaining parts
};

or more worse, the specialization might not have *any* inner class
val at all:

template <>
class foo<float> {};

For this reason can a compiler never deduce from a template
typedef back to the template parameter. A possible workaround
would be to write g as follows:

template <class T, class U>
void g(T& a, U& b)
{ std::cout << a.p<<","<<b.p<<"\n"; }

This might be unsatisfactory for you, because T and U are
unconstrained, but the point is, that the same applies for
foo<T>::val compared to foo<U>::val for every T different
from U.

A cleaner solution would be to separate the inner class
from the outer one:

template <class M>
class val { public: M p; };

template <class M>
class foo {
public:
  val<M> v;
  template <class N> void h(foo<N>& c);
};

template <class T, class U>
void g(val<T>& a, val<U>& b)
{ std::cout << a.p<<","<<b.p<<"\n"; }

Now the compiler can deduce T and U from the
following (unchanged) call to g.

Greetings from Bremen,

Daniel Kr   gler


---
[ 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.comeaucomputing.com/csc/faq.html                      ]