www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template member functions conflicting

reply Robin Allen <r.a3 ntlworld.com> writes:
class Bang(T)
{
	void fn(U)( Bang!(U) ot) {}
	
	void fn(int q) {}
}

Why do the two member functions conflict here? One takes a class 
instance and a type, the other takes an int.

If this is intended, and it's not possible to overload a function with a 
template function, then maybe it should be?
Feb 18 2007
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Robin Allen" <r.a3 ntlworld.com> wrote in message 
news:er9bin$1ksb$1 digitalmars.com...
 class Bang(T)
 {
 void fn(U)( Bang!(U) ot) {}

 void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class instance 
 and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function with a 
 template function, then maybe it should be?

The page http://www.digitalmars.com/d/template-comparison.html says that it's unfortunately not possible. What's worse, you can use specialized template functions as that page suggests, but then you surrender IFTI, so you will no longer be able to write "b.fn(4)" and have it automatically determine that you want the int version. You'll have to write "b.fn!(int)(4)". The reason this isn't possible (I've heard) is that function overloading and template specialization are two completely separate concepts, and getting them to work together is very hard indeed.
Feb 18 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
     
     void fn(int q) {}
 }
 
 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.
 
 If this is intended, and it's not possible to overload a function with a 
 template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); } -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Feb 19 2007
next sibling parent reply Aarti_pl <aarti interia.pl> writes:
Bruno Medeiros napisał(a):
 Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
         void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function with 
 a template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); }

Just a thought. Couldn't be normal functions just discarded in favor of templated versions (without need to write 2 pairs of parenthesis of course - I mean internally in compiler)? It would probably be much more consistent with templated versions... Best Regards Marcin Kuszczak
Feb 19 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Aarti_pl wrote:
 Bruno Medeiros napisał(a):
 Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
         void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function 
 with a template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); }

Just a thought. Couldn't be normal functions just discarded in favor of templated versions (without need to write 2 pairs of parenthesis of course - I mean internally in compiler)? It would probably be much more consistent with templated versions... Best Regards Marcin Kuszczak

Except that regular member functions and member function templates are not equivalent: Member function templates are implicitly "final," and are not entered into the vtable. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Feb 19 2007
parent Aarti_pl <aarti interia.pl> writes:
Kirk McDonald napisał(a):
 Except that regular member functions and member function templates are 
 not equivalent: Member function templates are implicitly "final," and 
 are not entered into the vtable.
 

I was expecting that there are different for some reasons :-) I am just thinking about improving it a little bit as I had to deal with overloading of template methods with normal functions and it is annoying.... Still, isn't it possible to make template functions like normal functions, so that they will not be 'final' by default? It would be probably also bonus for template functions itself... BR Marcin Kuszczak
Feb 19 2007
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bruno Medeiros" <brunodomedeiros+spam com.gmail> wrote in message 
news:erc3nr$2lis$1 digitalmars.com...
 They conflict, but there is an effective workaround, just turn the
 function into a nullary template (template with zero parameters):

 import stdext.stdio;

 class Bang(T)
 {
     void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); }
     void fn() (int q) { writeln("nullary template");}
 }


 void main(char[][] args) {
 auto foo = new Bang!(char);

 foo.fn(new Bang!(char));
 foo.fn(42);
 }

Huh! Pretty sweet. :)
Feb 19 2007
prev sibling parent reply Robin Allen <r.a3 ntlworld.com> writes:
Bruno Medeiros wrote:
 Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
         void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function with 
 a template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); }

I tried this, but for me it just crashes the compiler. Probably because it's actually opMul I'm defining rather than a normal function. (I'm trying to make a Matrix class that you can multiply by another matrix or a vector.) The actual code is more like this: class Matrix(int X,int Y,T) { Matrix!(X,OY,T) opMul(OY)( Matrix!(Y,OY,T) ot ); Vector!(Y,T) opMul( Vector!(X,T) vec ); } The only way I've been able to do it is by replacing one of the operator functions with a regular function. But it would be nice to do it with the * sign.
Feb 19 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Robin Allen wrote:
 Bruno Medeiros wrote:
 Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
         void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function 
 with a template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); }

I tried this, but for me it just crashes the compiler. Probably because it's actually opMul I'm defining rather than a normal function. (I'm trying to make a Matrix class that you can multiply by another matrix or a vector.) The actual code is more like this: class Matrix(int X,int Y,T) { Matrix!(X,OY,T) opMul(OY)( Matrix!(Y,OY,T) ot ); Vector!(Y,T) opMul( Vector!(X,T) vec ); } The only way I've been able to do it is by replacing one of the operator functions with a regular function. But it would be nice to do it with the * sign.

That won't typically work as you cannot overload on return types. If user code /only ever/ passed either Matrix or Vector with your opMul it might pass... but I'm dubious. In this case I would recommend just defining opMul for Matrix, and providing a function for multiplying with a Vector. The fact that it crashes the compiler, though, is another manner. Try to find a small test case that produces it and you may have a bug report to file. -- Chris Nicholson-Sauls
Feb 19 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Chris Nicholson-Sauls wrote:
 Robin Allen wrote:
 Bruno Medeiros wrote:
 Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
         void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function 
 with a template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); }

I tried this, but for me it just crashes the compiler. Probably because it's actually opMul I'm defining rather than a normal function. (I'm trying to make a Matrix class that you can multiply by another matrix or a vector.) The actual code is more like this: class Matrix(int X,int Y,T) { Matrix!(X,OY,T) opMul(OY)( Matrix!(Y,OY,T) ot ); Vector!(Y,T) opMul( Vector!(X,T) vec ); } The only way I've been able to do it is by replacing one of the operator functions with a regular function. But it would be nice to do it with the * sign.

That won't typically work as you cannot overload on return types.

No the rule is that you can't overload _only_ on return type. If the arguments are distinct then you can overload. This works for instance: struct Foo { int frob(int a) { return a; } char[] frob(char[] a) { return a; } } void main() { Foo f; int x = f.frob(3); char[] y = f.frob("hithere"); }
  If 
 user code /only ever/ passed either Matrix or Vector with your opMul it 
 might pass... but I'm dubious.  In this case I would recommend just 
 defining opMul for Matrix, and providing a function for multiplying with 
 a Vector.

 The fact that it crashes the compiler, though, is another manner.  Try 
 to find a small test case that produces it and you may have a bug report 
 to file.

Yeh, that sounds like a bug. File it here when you have a small repro case: http://d.puremagic.com/issues/ --bb
Feb 19 2007
parent Robin Allen <r.a3 ntlworld.com> writes:
My code's changed so much now I can't even reproduce the bug. It was 
probably caused by something way off in another file, like when I forgot 
a return statement and all my unittests crashed.

Also, I had (OY) by mistake, rather than (int OY). Template syntax is 
pretty confusing. I think I preferred C++'s (typename T) to D's (T). But 
that might be just me.

Bill Baxter wrote:
 Chris Nicholson-Sauls wrote:
 Robin Allen wrote:
 Bruno Medeiros wrote:
 Robin Allen wrote:
 class Bang(T)
 {
     void fn(U)( Bang!(U) ot) {}
         void fn(int q) {}
 }

 Why do the two member functions conflict here? One takes a class 
 instance and a type, the other takes an int.

 If this is intended, and it's not possible to overload a function 
 with a template function, then maybe it should be?

They conflict, but there is an effective workaround, just turn the function into a nullary template (template with zero parameters): import stdext.stdio; class Bang(T) { void fn(U)(Bang!(U) ot) { writeln("U template:", typeid(U) ); } void fn() (int q) { writeln("nullary template");} } void main(char[][] args) { auto foo = new Bang!(char); foo.fn(new Bang!(char)); foo.fn(42); }

I tried this, but for me it just crashes the compiler. Probably because it's actually opMul I'm defining rather than a normal function. (I'm trying to make a Matrix class that you can multiply by another matrix or a vector.) The actual code is more like this: class Matrix(int X,int Y,T) { Matrix!(X,OY,T) opMul(OY)( Matrix!(Y,OY,T) ot ); Vector!(Y,T) opMul( Vector!(X,T) vec ); } The only way I've been able to do it is by replacing one of the operator functions with a regular function. But it would be nice to do it with the * sign.

That won't typically work as you cannot overload on return types.

No the rule is that you can't overload _only_ on return type. If the arguments are distinct then you can overload. This works for instance: struct Foo { int frob(int a) { return a; } char[] frob(char[] a) { return a; } } void main() { Foo f; int x = f.frob(3); char[] y = f.frob("hithere"); }
  If user code /only ever/ passed either Matrix or Vector with your 
 opMul it might pass... but I'm dubious.  In this case I would 
 recommend just defining opMul for Matrix, and providing a function for 
 multiplying with a Vector.

 The fact that it crashes the compiler, though, is another manner.  Try 
 to find a small test case that produces it and you may have a bug 
 report to file.

Yeh, that sounds like a bug. File it here when you have a small repro case: http://d.puremagic.com/issues/ --bb

Feb 20 2007