www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template ref parameter

reply "Jack Applegame" <japplegame gmail.com> writes:
Why this could not compile?

struct Foo(T) {}
Foo!(ref int) foo;

Output:

Error: expression expected, not 'ref'
Error: found 'int' when expecting ')' following template argument 
list
Error: no identifier for declarator Foo!(0)
Error: semicolon expected, not ')'
Error: found ')' instead of statement
Nov 21 2012
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 21, 2012 11:55:53 Jack Applegame wrote:
 Why this could not compile?
 
 struct Foo(T) {}
 Foo!(ref int) foo;
 
 Output:
 
 Error: expression expected, not 'ref'
 Error: found 'int' when expecting ')' following template argument
 list
 Error: no identifier for declarator Foo!(0)
 Error: semicolon expected, not ')'
 Error: found ')' instead of statement

ref is not part of a type. It's only a storage class, and it's only legal on function parameters, return types, and foreach's loop variables. It's not legal on local variables or member variables or anything of the sort. So, ref int for a template argument makes no sense whatsoever. - Jonathan M Davis
Nov 21 2012
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
But sometimes ref becomes a part of type. For example "void 
delegate(ref int)" and "void delegate(int)" are different types. 
Is it possible to cast from one to another safely? For example:

void foo(ref int);
void function(int) fp;
fp = cast(typeof(fp)) foo; /// is it safe???
Nov 21 2012
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
How to implement functor-like objects if ref is storage class?

void foo(ref int a) { a--; }
struct functor(A...) {
   void function(A) functor;
}
functor!int f;    // functor!(ref int) - wrong
f.functor = &foo; // Error: cannot implicitly convert expression 
(& foo) of type void function(ref int a) to void function(int)
Nov 21 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Jack Applegame:

A brony? :-)

 But sometimes ref becomes a part of type. For example "void 
 delegate(ref int)" and "void delegate(int)" are different 
 types. Is it possible to cast from one to another safely? For 
 example:

 void foo(ref int);
 void function(int) fp;
 fp = cast(typeof(fp)) foo; /// is it safe???

In one case the function expects a pointer and in one case it expects a int value. The assembly code of the two functions is different and does different things. Bye, bearophile
Nov 21 2012
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
On Wednesday, 21 November 2012 at 12:05:23 UTC, bearophile wrote:
 In one case the function expects a pointer and in one case it 
 expects a int value. The assembly code of the two functions is 
 different and does different things.

Nov 21 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 21, 2012 12:57:57 Jack Applegame wrote:
 But sometimes ref becomes a part of type. For example "void
 delegate(ref int)" and "void delegate(int)" are different types.
 Is it possible to cast from one to another safely? For example:

That's because ref is being used on a function parameter. That gives the function a different type, but you can't just use ref int by itself. As I said, it's only applicable to function parameters, return types, and foreach loop variables.
 void foo(ref int);
 void function(int) fp;
 fp = cast(typeof(fp)) foo; /// is it safe???

No, it's not safe. - Jonathan M Davis
Nov 21 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, November 21, 2012 13:09:05 Jack Applegame wrote:
 On Wednesday, 21 November 2012 at 12:05:23 UTC, bearophile wrote:
 In one case the function expects a pointer and in one case it
 expects a int value. The assembly code of the two functions is
 different and does different things.

Of course. And it is mean that ref indeed is a part of type.

storage classes on function parameters affect the type of the function, but they do not affect the type of the parameter. If a function has a parameter named foo, then typeof(foo) is going to be the same whether ref is on it or not. - Jonathan M Davis
Nov 21 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 21 Nov 2012 12:02:45 -0000, Jack Applegame <japplegame gmail.com>  
wrote:

 void foo(ref int a) { a--; }
 struct functor(A...) {
   void function(A) functor;
 }
 functor!int f;    // functor!(ref int) - wrong
 f.functor = &foo; // Error: cannot implicitly convert expression (& foo)  
 of type void function(ref int a) to void function(int)

Hmm.. well I got past your initial problem, but I have a new one.. alias void function(ref int) funcType; void foo(ref int a) { a--; } struct functor(A...) { A func; } void main() { functor!funcType f; f.func = &foo; //Error: f.func is not an lvalue } -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 21 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 21 Nov 2012 12:30:08 -0000, Regan Heath <regan netmail.co.nz>  
wrote:

 On Wed, 21 Nov 2012 12:02:45 -0000, Jack Applegame  
 <japplegame gmail.com> wrote:

 void foo(ref int a) { a--; }
 struct functor(A...) {
   void function(A) functor;
 }
 functor!int f;    // functor!(ref int) - wrong
 f.functor = &foo; // Error: cannot implicitly convert expression (&  
 foo) of type void function(ref int a) to void function(int)

Hmm.. well I got past your initial problem, but I have a new one.. alias void function(ref int) funcType; void foo(ref int a) { a--; } struct functor(A...) { A func; } void main() { functor!funcType f; f.func = &foo; //Error: f.func is not an lvalue }

Just realised what is happening here. "f.func = " is trying to call the function, and assign &foo to the "void" result. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 21 2012
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
 storage classes on function parameters affect the type of the 
 function, but
 they do not affect the type of the parameter. If a function has 
 a parameter
 named foo, then typeof(foo) is going to be the same whether ref 
 is on it or
 not.

 - Jonathan M Davis

Ok. But how to pass storage class to template?
Nov 21 2012
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 21 Nov 2012 12:32:24 -0000, Regan Heath <regan netmail.co.nz>  
wrote:

 On Wed, 21 Nov 2012 12:30:08 -0000, Regan Heath <regan netmail.co.nz>  
 wrote:

 On Wed, 21 Nov 2012 12:02:45 -0000, Jack Applegame  
 <japplegame gmail.com> wrote:

 void foo(ref int a) { a--; }
 struct functor(A...) {
   void function(A) functor;
 }
 functor!int f;    // functor!(ref int) - wrong
 f.functor = &foo; // Error: cannot implicitly convert expression (&  
 foo) of type void function(ref int a) to void function(int)

Hmm.. well I got past your initial problem, but I have a new one.. alias void function(ref int) funcType; void foo(ref int a) { a--; } struct functor(A...) { A func; } void main() { functor!funcType f; f.func = &foo; //Error: f.func is not an lvalue }

Just realised what is happening here. "f.func = " is trying to call the function, and assign &foo to the "void" result.

Or not, duh! "A..." grr. alias void function(ref int) funcType; void foo(ref int a) { a--; } struct functor(A...) { A[0] func; } void main() { functor!funcType f; f.func = &foo; } R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 21 2012
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
This problem appears also in std.signals.
There is no possibility to use functions with ref parameters as 
signal handler.

import std.signals;

class Foo {
   mixin Signal!(int);
}
class Bar {
   void handler(ref int a) {}
}

void main() {
   Foo foo = new Foo;
   Bar bar = new Bar;
   foo.connect(&bar.handler);
}

outputs:
Error: function signals.Foo.Signal!(int).connect (void 
delegate(int) slot) is not callable using argument types (void 
delegate(ref int a))|
Error: cannot implicitly convert expression (&bar.handler) of 
type void delegate(ref int a) to void delegate(int)
Nov 21 2012
prev sibling next sibling parent "Jack Applegame" <japplegame gmail.com> writes:
 alias void function(ref int) funcType;

 void foo(ref int a) { a--; }

 struct functor(A...) {
   A[0] func;
 }
 void main()
 {
   functor!funcType f;
   f.func = &foo;
 }

I think the best way is using property. alias void function(ref int) funcType; void foo(ref int a) { a--; } struct functor(A...) { property void func(A fp) { m_func = fp; } A m_func; } void main() { functor!funcType f; f.func = &foo; }
Nov 21 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 11/21/12, Jack Applegame <japplegame gmail.com> wrote:
 This problem appears also in std.signals.
 There is no possibility to use functions with ref parameters as
 signal handler.

 import std.signals;

 class Foo {
    mixin Signal!(int);
 }
 class Bar {
    void handler(ref int a) {}
 }

 void main() {
    Foo foo = new Foo;
    Bar bar = new Bar;
    foo.connect(&bar.handler);
 }

Known problem, no known proposals or solutions. But there are workarounds, e.g. if you're writing your own signals implementation you could use a function type instead of a lone type, e.g.: mixin Signal!(void function(ref int));
Nov 21 2012
prev sibling parent "Jack Applegame" <japplegame gmail.com> writes:
Ugly C++ like template and mixin magic solution:

struct r(T){ alias T type;}
template str(alias A) if(is(A == r!(A.type))) { const char[] str 
= "ref " ~ A.type.stringof; }
template str(T) { const char[] str = T.stringof; }
template str(T, A...) { const char[] str = str!T ~ ", " ~ str!A; }

struct functor(A...) {
   void opAssign(C)(C callable) { m_fp = callable; }
   void opCall(R...)(auto ref R r) { m_fp(r); }
   private {
     mixin("void function(" ~ str!A ~ ") m_fp;");
   }
}

void foo(ref int a, int b) { a += b; }

void main()
{
   functor!(r!int, int) f;
   f = &foo;
   int a = 1, b = 2;
   f(a, b);
   assert(a == 3);
}
Nov 21 2012