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 ]