Hi,
There is a difference between
A.1) syntax of template (usual) function without arguments
A.2) syntax of template (usual) function with some (not all) arguments
A.3) syntax of template (usual) function with all arguments
B.1) syntax of template member function without arguments
B.2) syntax of template member function with some (not all) arguments
B.3) syntax of template member function with all arguments
This difference is demonstrated in the following example.
Alex
###################################################
############# 1. jp_class.H #######################
###################################################
#include <string>
//############################################
// template (usual) function without arguments
template <typename T1, typename T2>
void foo_no()
{
cout << __PRETTY_FUNCTION__ << " \t: No input parameters" << endl;
// __PRETTY_FUNCTION__ is predefined string variable in gcc/g++
}
//############################################
// template (usual) function only with first argument
template <typename T1, typename T2>
void foo_1(T1 &first)
{
cout << __PRETTY_FUNCTION__ << " \t: arg1 = " << first << endl;
}
//############################################
// template (usual) function only with second argument
template <typename T1, typename T2>
void foo_2(T2 &second)
{
cout << __PRETTY_FUNCTION__ << " \t: arg2 = " << second << endl;
}
//############################################ // template (usual) function
with all arguments template <typename T1, typename T2> void foo_all(T1
&first, T2 &second) { cout << __PRETTY_FUNCTION__ << " \t: arg1 = " << first
<< ", arg2 = " << second << endl; }
//############################################
class MyClass
{
public:
MyClass () {}
~MyClass () {}
//------------------------------------------
// template member function without arguments
template <typename T1, typename T2>
void Foo_no();
//------------------------------------------
// template member function only with first argument
template <typename T1, typename T2>
void Foo_1(T1 &first);
//------------------------------------------
// template member function only with second argument
template <typename T1, typename T2>
void Foo_2(T2 &second);
//------------------------------------------
// template member function only with all arguments
template <typename T1, typename T2>
void Foo_all(T1 &first, T2 &second);
};
//############################################
// template member function without arguments
template <typename T1, typename T2>
void MyClass::Foo_no()
{
cout << __PRETTY_FUNCTION__ << " \t: No input parameters" << endl;
}
//############################################
// template member function only with first argument
template <typename T1, typename T2>
void MyClass::Foo_1(T1 &first)
{
cout << __PRETTY_FUNCTION__ << " \t: Arg1 = " << first << endl;
}
//############################################
// template member function only with second argument
template <typename T1, typename T2>
void MyClass::Foo_2(T2 &second)
{
cout << __PRETTY_FUNCTION__ << " \t: Arg2 = " << second << endl;
}
//############################################ // template member function
with all arguments template <typename T1, typename T2> void
MyClass::Foo_all(T1 &first, T2 &second) { cout << __PRETTY_FUNCTION__ << "
\t: Arg1 = " << first << ", Arg2 = " << second << endl; }
###################################################
############# 2. MyClass.cpp ######################
###################################################
#include "jp_class.H"
// The file has no implementation (in this example)
###################################################
############# 3. jp_main.C ########################
###################################################
#include "jp_class.H"
int main ()
{
MyClass object;
int i11 = 11;
int i12 = 12;
int i21 = 21;
int i22 = 22;
int i31 = 31;
int i32 = 32;
int i41 = 41;
int i42 = 42;
char* c11 = "one_aaaaa";
char* c12 = "one_bbbbb";
char* c21 = "two_aaaaa";
char* c22 = "two_bbbbb";
char* c31 = "three_aaaaa";
char* c32 = "three_bbbbb";
char* c41 = "four_aaaaa";
char* c42 = "four_bbbbb";
//##############################################
//##############################################
cout << endl;
cout << endl;
cout << "###### foo_no : template (usual) function without arguments
######" << endl;
cout << " All template types are explicit" << endl;
foo_no<int, int> ();
foo_no<int, char*> ();
foo_no<char*, int> ();
foo_no<char*, char*> ();
//==============================================
cout << endl;
cout << endl;
cout << "###### foo_1 : template (usual) function only with first
argument ######" << endl;
cout << " All template types are explicit" << endl;
foo_1<int, int> (i11);
foo_1<int, char*> (i21);
foo_1<char*, int> (c31);
foo_1<char*, char*> (c41);
//==============================================
cout << endl;
cout << endl;
cout << "###### foo_2 : template (usual) function only with second
argument ######" << endl;
cout << " All template types are explicit" << endl;
foo_2<int, int> (i12);
foo_2<int, char*> (c22);
foo_2<char*, int> (i32);
foo_2<char*, char*> (c42);
cout << endl;
cout << " First template type is explicit" << endl;
cout << " Second template type is implicit (defined according to the
arg2 type)" << endl;
foo_2<int> (i12);
foo_2<int> (c22);
foo_2<char*> (i32);
foo_2<char*> (c42);
//==============================================
cout << endl;
cout << endl;
cout << "###### foo_all : template (usual) function with all arguments
######" << endl;
cout << " All template types are explicit" << endl;
foo_all<int, int> (i11, i12);
foo_all<int, char*> (i21, c22);
foo_all<char*, int> (c31, i32);
foo_all<char*, char*> (c41, c42);
cout << endl;
cout << " First template type is explicit" << endl;
cout << " Second template type is implicit (defined according to the
arg2 type)" << endl;
foo_all<int> (i11, i12);
foo_all<int> (i21, c22);
foo_all<char*> (c31, i32);
foo_all<char*> (c41, c42);
cout << endl;
cout << " All template types are implicit (defined according to the
arguments types)" << endl;
foo_all (i11, i12);
foo_all (i21, c22);
foo_all (c31, i32);
foo_all (c41, c42);
//##############################################
//##############################################
cout << endl;
cout << endl;
cout << "###### object.Foo_no : template member function without
arguments ######" << endl;
cout << " All template types are explicit" << endl;
object.template Foo_no<int, int> ();
object.template Foo_no<int, char*> ();
object.template Foo_no<char*, int> ();
object.template Foo_no<char*, char*> ();
//============================================== cout << endl; cout <<
endl; cout << "###### object.Foo_1 : template member function only with
first argument ######" << endl; cout << " All template types are explicit"
<< endl; object.template Foo_1<int, int> (i11); object.template Foo_1<int,
char*> (i21); object.template Foo_1<char*, int> (c31); object.template
Foo_1<char*, char*> (c41);
//============================================== cout << endl; cout <<
endl; cout << "###### object.Foo_2 : template member function only with
second argument ######" << endl; cout << " All template types are explicit"
<< endl; object.template Foo_2<int, int> (i12); object.template Foo_2<int,
char*> (c22); object.template Foo_2<char*, int> (i32); object.template
Foo_2<char*, char*> (c42);
cout << endl;
cout << " First template type is explicit" << endl;
cout << " Second template type is implicit (defined according to the
arg2 type)" << endl;
object.template Foo_2<int> (i12);
object.template Foo_2<int> (c22);
object.template Foo_2<char*> (i31);
object.template Foo_2<char*> (c41);
//==============================================
cout << endl;
cout << endl;
cout << "###### object.Foo_all : template member function with all
arguments ######" << endl;
cout << " All template types are explicit" << endl;
object.template Foo_all<int, int> (i11, i12);
object.template Foo_all<int, char*> (i21, c22);
object.template Foo_all<char*, int> (c31, i32);
object.template Foo_all<char*, char*> (c41, c42);
cout << endl;
cout << " First template type is explicit" << endl;
cout << " Second template type is implicit (defined according to the
arg2 type)" << endl;
object.template Foo_all<int> (i11, i12);
object.template Foo_all<int> (i21, c22);
object.template Foo_all<char*> (c31, i32);
object.template Foo_all<char*> (c41, c42);
cout << endl;
cout << " All template types are implicit (defined according to the
arguments types)" << endl;
// ATTENTION! not object.template Foo_all (v1, v2), but object.Foo_all
(v1, v2)
object.Foo_all (i11, i12);
object.Foo_all (i21, c22);
object.Foo_all (c31, i32);
object.Foo_all (c41, c42);
//========================
return 0;
}
###################################################
############# 4. Compiler #########################
###################################################
g++ -v : gcc version egcs-2.91.57 19980901 (egcs-1.1 release)
###################################################
############# 5. Hardware #########################
###################################################
uname -a : SunOS tibamsun8 5.6 Generic_105181-09 sun4m sparc
SUNW,SPARCstation-5
###################################################
############# 6. Results of the running ##########
###################################################
###### foo_no : template (usual) function without arguments ######
All template types are explicit
void foo_no<int, int>() : No input parameters
void foo_no<int, char *>() : No input parameters
void foo_no<char *, int>() : No input parameters
void foo_no<char *, char *>() : No input parameters
###### foo_1 : template (usual) function only with first argument ######
All template types are explicit
void foo_1<int, int>(int &) : arg1 = 11
void foo_1<int, char *>(int &) : arg1 = 21
void foo_1<char *, int>(char *&) : arg1 = three_aaaaa
void foo_1<char *, char *>(char *&) : arg1 = four_aaaaa
###### foo_2 : template (usual) function only with second argument ######
All template types are explicit
void foo_2<int, int>(int &) : arg2 = 12
void foo_2<int, char *>(char *&) : arg2 = two_bbbbb
void foo_2<char *, int>(int &) : arg2 = 32
void foo_2<char *, char *>(char *&) : arg2 = four_bbbbb
First template type is explicit
Second template type is implicit (defined according to the arg2 type)
void foo_2<int, int>(int &) : arg2 = 12
void foo_2<int, char *>(char *&) : arg2 = two_bbbbb
void foo_2<char *, int>(int &) : arg2 = 32
void foo_2<char *, char *>(char *&) : arg2 = four_bbbbb
###### foo_all : template (usual) function with all arguments ###### All
template types are explicit void foo_all<int, int>(int &, int &) : arg1 =
11, arg2 = 12 void foo_all<int, char *>(int &, char *&) : arg1 = 21, arg2
= two_bbbbb void foo_all<char *, int>(char *&, int &) : arg1 = three_aaaaa,
arg2 = 32 void foo_all<char *, char *>(char *&, char *&) : arg1 =
four_aaaaa, arg2 = four_bbbbb
First template type is explicit Second template type is implicit (defined
according to the arg2 type) void foo_all<int, int>(int &, int &) : arg1 =
11, arg2 = 12 void foo_all<int, char *>(int &, char *&) : arg1 = 21, arg2
= two_bbbbb void foo_all<char *, int>(char *&, int &) : arg1 = three_aaaaa,
arg2 = 32 void foo_all<char *, char *>(char *&, char *&) : arg1 =
four_aaaaa, arg2 = four_bbbbb
All template types are implicit (defined according to the arguments types)
void foo_all<int, int>(int &, int &) : arg1 = 11, arg2 = 12 void
foo_all<int, char *>(int &, char *&) : arg1 = 21, arg2 = two_bbbbb void
foo_all<char *, int>(char *&, int &) : arg1 = three_aaaaa, arg2 = 32 void
foo_all<char *, char *>(char *&, char *&) : arg1 = four_aaaaa, arg2 =
four_bbbbb
###### object.Foo_no : template member function without arguments ######
All template types are explicit
void MyClass::Foo_no<int, int>() : No input parameters
void MyClass::Foo_no<int, char *>() : No input parameters
void MyClass::Foo_no<char *, int>() : No input parameters
void MyClass::Foo_no<char *, char *>() : No input parameters
###### object.Foo_1 : template member function only with first argument ######
All template types are explicit
void MyClass::Foo_1<int, int>(int &) : Arg1 = 11
void MyClass::Foo_1<int, char *>(int &) : Arg1 = 21
void MyClass::Foo_1<char *, int>(char *&) : Arg1 = three_aaaaa
void MyClass::Foo_1<char *, char *>(char *&) : Arg1 = four_aaaaa
###### object.Foo_2 : template member function only with second argument
###### All template types are explicit void MyClass::Foo_2<int, int>(int &)
: Arg2 = 12 void MyClass::Foo_2<int, char *>(char *&) : Arg2 = two_bbbbb
void MyClass::Foo_2<char *, int>(int &) : Arg2 = 32 void MyClass::Foo_2<char
*, char *>(char *&) : Arg2 = four_bbbbb
First template type is explicit
Second template type is implicit (defined according to the arg2 type)
void MyClass::Foo_2<int, int>(int &) : Arg2 = 12
void MyClass::Foo_2<int, char *>(char *&) : Arg2 = two_bbbbb
void MyClass::Foo_2<char *, int>(int &) : Arg2 = 31
void MyClass::Foo_2<char *, char *>(char *&) : Arg2 = four_aaaaa
###### object.Foo_all : template member function with all arguments ######
All template types are explicit
void MyClass::Foo_all<int, int>(int &, int &) : Arg1 = 11, Arg2 = 12
void MyClass::Foo_all<int, char *>(int &, char *&) : Arg1 = 21, Arg2 =
two_bbbbb
void MyClass::Foo_all<char *, int>(char *&, int &) : Arg1 = three_aaaaa,
Arg2 = 32
void MyClass::Foo_all<char *, char *>(char *&, char *&) : Arg1 =
four_aaaaa, Arg2 = four_bbbbb
First template type is explicit
Second template type is implicit (defined according to the arg2 type)
void MyClass::Foo_all<int, int>(int &, int &) : Arg1 = 11, Arg2 = 12
void MyClass::Foo_all<int, char *>(int &, char *&) : Arg1 = 21, Arg2 =
two_bbbbb
void MyClass::Foo_all<char *, int>(char *&, int &) : Arg1 = three_aaaaa,
Arg2 = 32
void MyClass::Foo_all<char *, char *>(char *&, char *&) : Arg1 =
four_aaaaa, Arg2 = four_bbbbb
All template types are implicit (defined according to the arguments types)
void MyClass::Foo_all<int, int>(int &, int &) : Arg1 = 11, Arg2 = 12
void MyClass::Foo_all<int, char *>(int &, char *&) : Arg1 = 21, Arg2 =
two_bbbbb
void MyClass::Foo_all<char *, int>(char *&, int &) : Arg1 = three_aaaaa,
Arg2 = 32
void MyClass::Foo_all<char *, char *>(char *&, char *&) : Arg1 =
four_aaaaa, Arg2 = four_bbbbb
###################################################
############# END of INFORMATION #################
###################################################
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
You are right.
Thank you.
>
> From the current C++-Standard, I couldn't find any part
> (expected somewhere in 14.5.5.2 Partial ordering of
> function templates) that gives an answer.
> This means the behaviour is unspecified.
>
> However, egcs-1.1.1 resolves the call in presence of #2a
> foo_2<int>(i11); --> foo_2<int,int>(int &);// arg=T2 !!
> with the 2nd _not_choosen_ possible call to
> foo_2<int>(int &);
> and _no_ ambiguity diagnosed.
>
> Egcs seems to think foo_2<int,int> is more specialized
> than foo_2<int>, what's a reasonable choice,
> but common sense will be surprised.
>
> --ALfred
>
> [ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> [ about comp.lang.c++.moderated. First time posters: do this! ]
>
I would like to accentuate the importance of this problem on the following
example.
Alex
###################################################
############# 1. jp2_class.H ######################
###################################################
#include <string>
//############################################
// template (usual) function : one template-type; 2) with argument
template <typename T1>
void foo_1(T1 &first)
{
cout << __PRETTY_FUNCTION__ << " \t: arg = " << first << endl;
}
//############################################
// template (usual) function : two template-types; 2) only with first argument
template <typename T1, typename T2>
void foo_1(T1 &first)
{
cout << __PRETTY_FUNCTION__ << " \t: arg1 = " << first << endl;
}
//############################################
// template (usual) function : one template-type; 2) with argument
template <typename T2>
void foo_2(T2 &second)
{
cout << __PRETTY_FUNCTION__ << " \t: arg = " << second << endl;
}
//############################################
// template (usual) function : one template-type; 2) with argument
template <typename T2>
void foo_2A(T2 &second)
{
cout << __PRETTY_FUNCTION__ << " \t: arg = " << second << endl;
}
//############################################ // template (usual) function :
two template-types; 2) only with second argument template <typename T1,
typename T2> void foo_2(T2 &second) { cout << __PRETTY_FUNCTION__ << " \t:
arg2 = " << second << endl; }
###################################################
############# 2. jp2_class.cpp ####################
###################################################
#include "jp2_class.H"
// The file has no implementation (in this example)
###################################################
############# 3. jp2_main.C #######################
###################################################
#include "jp2_class.H"
int main ()
{
int i11 = 11;
int i12 = 12;
int i21 = 21;
int i32 = 32;
char* c21 = "two_aaaaa";
char* c22 = "two_bbbbb";
char* c31 = "three_aaaaa";
char* c41 = "four_aaaaa";
char* c42 = "four_bbbbb";
//##############################################
//##############################################
//==============================================
cout << endl;
cout << endl;
cout << "#############################" << endl;
cout << "###### foo_1 functions ######" << endl;
cout << "#############################" << endl;
cout << "###### foo_1<T1, T2> (T1& arg) ######" << endl;
cout << "====== All template types are explicit" << endl;
foo_1<int, int> (i11);
foo_1<int, char*> (i21);
foo_1<char*, int> (c31);
foo_1<char*, char*> (c41);
//==============================================
cout << endl;
cout << endl;
cout << "###### foo_1<T> (T& arg) ######" << endl;
cout << "====== The template type is explicit" << endl;
foo_1<int> (i11);
foo_1<char*> (c21);
//==============================================
cout << endl;
cout << "====== The template type is implicit" << endl;
foo_1 (i11);
foo_1 (c21);
//==============================================
cout << endl;
cout << endl;
cout << "#############################" << endl;
cout << "###### foo_2 functions ######" << endl;
cout << "#############################" << endl;
cout << "###### foo_2<T1, T2> (T2& arg) ######" << endl;
cout << "====== All template types are explicit" << endl;
foo_2<int, int> (i12);
foo_2<int, char*> (c22);
foo_2<char*, int> (i32);
foo_2<char*, char*> (c42);
cout << endl;
cout << "====== First template type is explicit" << endl;
cout << "====== Second template type is implicit (defined according to
the arg2 type)" << endl;
foo_2<int> (i12);
foo_2<int> (c22);
foo_2<char*> (i32);
foo_2<char*> (c42);
//============================================== cout << endl; cout <<
endl; cout << "###### foo_2<T> (T& arg) ######" << endl; cout << "======
The template type is explicit" << endl; foo_2<int> (i12); foo_2<int> (c22);
foo_2<char*> (i32); foo_2<char*> (c42); cout << "------ CONCLUSION : This
is not the foo_2<T> (T& arg) function" << endl; cout << "------ : This is
foo_2<T1, T2> (T2& arg) function" << endl;
//============================================== cout << endl; cout <<
"====== The template type is implicit" << endl; foo_2 (i11); foo_2 (c21);
cout << "------ CONCLUSION : This is the foo_2<T> (T& arg) function" << endl;
//============================================== cout << endl; cout <<
endl; cout << "###### foo_2A<T> (T& arg) ######" << endl; cout << "======
The template type is explicit" << endl; foo_2A<int> (i12); foo_2A<char*>
(c22); cout << "------ CONCLUSION : This is the foo_2A<T> (T& arg) function"
<< endl;
//============================================== cout << endl; cout <<
"====== The template type is implicit" << endl; foo_2A (i11); foo_2A (c21);
cout << "------ CONCLUSION : This is the foo_2A<T> (T& arg) function" <<
endl;
//==============================================
//========================
return 0;
}
###################################################
############# 4. Compiler #########################
###################################################
g++ -v : gcc version egcs-2.91.57 19980901 (egcs-1.1 release)
###################################################
############# 5. Hardware #########################
###################################################
uname -a : SunOS tibamsun8 5.6 Generic_105181-09 sun4m sparc
SUNW,SPARCstation-5
###################################################
############# 6. Results of the running ##########
###################################################
#############################
###### foo_1 functions ######
#############################
###### foo_1<T1, T2> (T1& arg) ######
====== All template types are explicit
void foo_1<int, int>(int &) : arg1 = 11
void foo_1<int, char *>(int &) : arg1 = 21
void foo_1<char *, int>(char *&) : arg1 = three_aaaaa
void foo_1<char *, char *>(char *&) : arg1 = four_aaaaa
###### foo_1<T> (T& arg) ######
====== The template type is explicit
void foo_1<int>(int &) : arg = 11
void foo_1<char *>(char *&) : arg = two_aaaaa
====== The template type is implicit
void foo_1<int>(int &) : arg = 11
void foo_1<char *>(char *&) : arg = two_aaaaa
#############################
###### foo_2 functions ######
#############################
###### foo_2<T1, T2> (T2& arg) ######
====== All template types are explicit
void foo_2<int, int>(int &) : arg2 = 12
void foo_2<int, char *>(char *&) : arg2 = two_bbbbb
void foo_2<char *, int>(int &) : arg2 = 32
void foo_2<char *, char *>(char *&) : arg2 = four_bbbbb
====== First template type is explicit
====== Second template type is implicit (defined according to the arg2 type)
void foo_2<int, int>(int &) : arg2 = 12
void foo_2<int, char *>(char *&) : arg2 = two_bbbbb
void foo_2<char *, int>(int &) : arg2 = 32
void foo_2<char *, char *>(char *&) : arg2 = four_bbbbb
###### foo_2<T> (T& arg) ######
====== The template type is explicit
void foo_2<int, int>(int &) : arg2 = 12
void foo_2<int, char *>(char *&) : arg2 = two_bbbbb
void foo_2<char *, int>(int &) : arg2 = 32
void foo_2<char *, char *>(char *&) : arg2 = four_bbbbb
------ CONCLUSION : This is not the foo_2<T> (T& arg) function
------ : This is foo_2<T1, T2> (T2& arg) function
====== The template type is implicit
void foo_2<int>(int &) : arg = 11
void foo_2<char *>(char *&) : arg = two_aaaaa
------ CONCLUSION : This is the foo_2<T> (T& arg) function
###### foo_2A<T> (T& arg) ######
====== The template type is explicit
void foo_2A<int>(int &) : arg = 12
void foo_2A<char *>(char *&) : arg = two_bbbbb
------ CONCLUSION : This is the foo_2A<T> (T& arg) function
====== The template type is implicit
void foo_2A<int>(int &) : arg = 11
void foo_2A<char *>(char *&) : arg = two_aaaaa
------ CONCLUSION : This is the foo_2A<T> (T& arg) function
###################################################
############# 7. Local Conclusions ################
###################################################
1. Two foo_1 (...) functions.
The functions template resolution is always specified & expected.
2. Two foo_2 (...) functions.
2.1) The functions template resolution is specified & expected
when using implicit template types (if it is possible).
^^^^^^^^
2.2) The foo_2<T1, T2> (T2& arg) function template resolution
is specified & expected
when using explicit template types.
^^^^^^^^
2.3) The foo_2<T> (T& arg) function template resolution
is impossible (as foo_2<T> (T& arg) function)
when using explicit template types.
^^^^^^^^
Note. The compiler resolves this
as foo_2<T1, T2> (T2& arg) function.
3. One foo_2A (...) function.
The function template resolution is always specified & expected.
###################################################
############# 8. Common Conclusions ###############
###################################################
1. Using the explicit template types
can cause unexpected resolution of function template.
2. Using the implicit template types (when it is possible)
always causes expected resolution of function template.
###################################################
############# 9. Question #########################
###################################################
1. Is the compiler behavior compiler-depended?
2. Is the compiler behavior planned?