precedence of template funtion over non-template function?

Hi!

It seems that a template-function has always precedence over a non-template function if the function argument doesn't match the type of the non-template function's argument exactly, but is a derived type, i.e., with the declarations

1
2
3
4
5
struct A { ... };
struct B: A { ... };
B object;
template <typename T> void func(const T &x);
void func(const A &x);


calling func(object) uses the template variant of func(), only func((A&)object) uses the non-template variant.

So my question is: is there any way to modify the declarations such that func(object) uses the non-template variant, even if "object" is an instance of a derived type of A?

Thanks & kind regards,
Markus


P.S.: here is a full example demonstrating the above-mentioned behaviour:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>

using namespace std;


struct A
{
	virtual void func() const { cout << "void A::func() const\n"; }
};

struct B: A
{
	void func() const { cout << "void B::func() const\n"; }
};

struct C
{
	void func() const { cout << "void C::func() const\n" << endl; }
};

template <typename T> void func(const T &x)
{
	cout << "template <typename T> void func(const T &x)\n";
	x.func();
};

void func(const A &x)
{
	cout << "void func(const A &x)\n";
	x.func();
};

void main()
{
	A a;
	B b;
	C c;
	func(a);
	func(b);
	func((A &)b);
	func(c);
}
Last edited on
That is odd. According to "C++ Templates: The Complete Guide" (Vandervoorde & Josuttis):

...a nontemplate function can coexist with a function template that has the same name and parameters and can be instantiated with the same type. All other factors being equal, the overload resolution process normally prefers this nontemplate over one generated from the template.


edit: Just tested it myself.


$ ./a
void func(const A &x)
void A::func() const
template <typename T> void func(const T &x)
void B::func() const
void func(const A &x)
void B::func() const
template <typename T> void func(const T &x)
void C::func() const


This appears to be the correct output with the nontemplate taking precedence? Perhaps it is compiler specific? I was using gnu.
Last edited on
The statement "func(b);" in line 39 of the code example calls the template function, which corresponds to the 3rd line in your program output. Only if the object is explicitly cast to the base class ("func((A &)b);" in line 40), the non-template function is called (5th line in your output).

BTW, I tried the example with MSVC2005 and gcc-4.5 (MinGW) and got results identical to your posted output. I would like to see

void func(const A &x)
void A::func() const
void func(const A &x)
void B::func() const
void func(const A &x)
void B::func() const
template <typename T> void func(const T &x)
void C::func() const


instead (note the difference in the 3rd line). Can this be done without an explicit cast (as in "func((A &)b);")?

Thanks & kind regards,
Markus
Last edited on
Not tested:
1
2
3
4
5
6
7
8
9
10
template <typename T> void func(const T *x);
void func(const A *x);

int main(){
  A *ptr;
  ptr = new B;
  func( ptr );
  delete ptr;
  return 0; 
}
This certainly works (I rewrote the example using pointers, see below), but the objects I want to pass into the function are not created as pointers, and rewriting the entire code using new/delete is not an option. So my question is still open, do you have further ideas (or at least a clarification that it is not possible at all)?

Thanks & kind regards,
Markus


P.S.: here is the updated code example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>

using namespace std;


struct A
{
	virtual void func() const { cout << "void A::func() const\n"; }
};

struct B: A
{
	void func() const { cout << "void B::func() const\n"; }
};

struct C
{
	void func() const { cout << "void C::func() const\n"; }
};

template <typename T> void func(const T *x)
{
	cout << "template <typename T> void func(const T *x)\n";
	x->func();
};

void func(const A *x)
{
	cout << "void func(const A *x)\n";
	x->func();
};

int main()
{
	A *a = new A;
	B *b = new B;
	C *c = new C;
	A *d = new B;
	func(a);
	func(b);
	func((A *)b);
	func(c);
	func(d);
	delete a;
	delete b;
	delete c;
	delete d;
	return 0;
}

All other factors being equal, the overload resolution process normally prefers this nontemplate over one generated from the template.
They are not the same, because implies an implicit conversion.
Instead of executing the implicit conversion, the code is generated trough the template (maybe is implementation dependent)

You could do a wrapper for every derived class
1
2
3
void func(const B &x){
  func( (A &)x );
}
Thanks for the proposal, this is what I am currently doing. However, it is somewhat inconvenient and error prone, so I would prefer if it could be done automatically, i.e., if I could somehow tell the compiler to prefer the function which takes the base class pointer (or reference) argument over the template function. Is there any way of doing this?

Thanks & kind regards,
Markus
Topic archived. No new replies allowed.