Jump to page: 1 2
Thread overview
Template member functions conflicting
Feb 18, 2007
Robin Allen
Feb 19, 2007
Bruno Medeiros
Feb 19, 2007
Aarti_pl
Feb 19, 2007
Kirk McDonald
Feb 19, 2007
Aarti_pl
Feb 19, 2007
Robin Allen
Feb 19, 2007
Bill Baxter
Feb 20, 2007
Robin Allen
February 18, 2007
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?
February 18, 2007
"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.


February 19, 2007
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
February 19, 2007
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
February 19, 2007
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
February 19, 2007
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
February 19, 2007
"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.  :)


February 19, 2007
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.


February 19, 2007
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
February 19, 2007
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
« First   ‹ Prev
1 2