www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to call opCall as template?

reply "Namespace" <rswhite4 googlemail.com> writes:
Here: http://dlang.org/operatoroverloading.html#FunctionCall
is this example:
----
import std.stdio;

struct F {
	int opCall() {
		return 0;
	}
	
	int opCall(int x, int y, int z) {
		return x * y * z;
	}
}

void main() {
	F f;
	int i;

	i = f();      // same as i = f.opCall();
	i = f(3,4,5); // same as i = f.opCall(3,4,5);
}
----

And it works of course. But what if I want to templatize opCall? 
How can I call it?

----
import std.stdio;

struct F {
	T opCall(T = int)(int a, int b, int c) {
		return cast(T)(a * b * c);
	}
}

void main() {
	F f;
	int i = f(3,4,5);
	float f_ = f!float(6, 7, 8);
}
----

Does not work, it fails with:
Error: template instance f!float f is not a template declaration, 
it is a variable
Jan 30 2014
next sibling parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
f.opCall!float(6, 7, 8);
Jan 30 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 30 January 2014 at 16:24:00 UTC, Stanislav Blinov 
wrote:
 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
f.opCall!float(6, 7, 8);
... Yes, of course. But where is the sense to use opCall if I need to call it explicitly?
Jan 30 2014
parent reply "Frustrated" <c1514843 drdrb.com> writes:
On Thursday, 30 January 2014 at 16:28:42 UTC, Namespace wrote:
 On Thursday, 30 January 2014 at 16:24:00 UTC, Stanislav Blinov 
 wrote:
 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
f.opCall!float(6, 7, 8);
... Yes, of course. But where is the sense to use opCall if I need to call it explicitly?
Could you not use opDispatch? Not sure if you can templatize it or not though...
Jan 30 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 30 January 2014 at 16:47:46 UTC, Frustrated wrote:
 On Thursday, 30 January 2014 at 16:28:42 UTC, Namespace wrote:
 On Thursday, 30 January 2014 at 16:24:00 UTC, Stanislav Blinov 
 wrote:
 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
f.opCall!float(6, 7, 8);
... Yes, of course. But where is the sense to use opCall if I need to call it explicitly?
Could you not use opDispatch? Not sure if you can templatize it or not though...
Example? I did not know how.
Jan 30 2014
parent "Frustrated" <c1514843 drdrb.com> writes:
On Thursday, 30 January 2014 at 16:53:33 UTC, Namespace wrote:
 On Thursday, 30 January 2014 at 16:47:46 UTC, Frustrated wrote:
 On Thursday, 30 January 2014 at 16:28:42 UTC, Namespace wrote:
 On Thursday, 30 January 2014 at 16:24:00 UTC, Stanislav 
 Blinov wrote:
 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
f.opCall!float(6, 7, 8);
... Yes, of course. But where is the sense to use opCall if I need to call it explicitly?
Could you not use opDispatch? Not sure if you can templatize it or not though...
Example? I did not know how.
doesn't seem to work with templates, I suppose you could try and add it as a feature request? module main; import std.stdio; interface A { void foo(); static final New() { } } class B : A { void foo() { writeln("this is B.foo"); } void opDispatch(string s, T)(int i) { writefln("C.opDispatch('%s', %s)", s, i); } } void main() { B a = new B; //a.foo(); a.test!int(3); // any *good* reason why this shouldn't work? }
Jan 30 2014
prev sibling parent reply "Meta" <jared771 gmail.com> writes:
On Thursday, 30 January 2014 at 15:59:28 UTC, Namespace wrote:
 Here: http://dlang.org/operatoroverloading.html#FunctionCall
 is this example:
 ----
 import std.stdio;

 struct F {
 	int opCall() {
 		return 0;
 	}
 	
 	int opCall(int x, int y, int z) {
 		return x * y * z;
 	}
 }

 void main() {
 	F f;
 	int i;

 	i = f();      // same as i = f.opCall();
 	i = f(3,4,5); // same as i = f.opCall(3,4,5);
 }
 ----

 And it works of course. But what if I want to templatize 
 opCall? How can I call it?

 ----
 import std.stdio;

 struct F {
 	T opCall(T = int)(int a, int b, int c) {
 		return cast(T)(a * b * c);
 	}
 }

 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
This is probably a bug. You should file it in Bugzilla.
Jan 30 2014
next sibling parent reply "Frustrated" <c1514843 drdrb.com> writes:
Also,

http://dlang.org/operatoroverloading.html#Dispatch

and possible solution to your problem:

http://www.digitalmars.com/d/archives/digitalmars/D/opDispatch_and_template_parameters_117095.html

Couldn't get code to compile though... but if it did, it should
solve your problem.
Jan 30 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 30 January 2014 at 17:46:19 UTC, Frustrated wrote:
 Also,

 http://dlang.org/operatoroverloading.html#Dispatch

 and possible solution to your problem:

 http://www.digitalmars.com/d/archives/digitalmars/D/opDispatch_and_template_parameters_117095.html

 Couldn't get code to compile though... but if it did, it should
 solve your problem.
opDispatch is called if you try to call a non existing member. But in this case you don't call a member. ;)
Jan 30 2014
parent reply "Frustrated" <c1514843 drdrb.com> writes:
On Thursday, 30 January 2014 at 18:02:05 UTC, Namespace wrote:
 On Thursday, 30 January 2014 at 17:46:19 UTC, Frustrated wrote:
 Also,

 http://dlang.org/operatoroverloading.html#Dispatch

 and possible solution to your problem:

 http://www.digitalmars.com/d/archives/digitalmars/D/opDispatch_and_template_parameters_117095.html

 Couldn't get code to compile though... but if it did, it should
 solve your problem.
opDispatch is called if you try to call a non existing member. But in this case you don't call a member. ;)
Right, but maybe you can use the same technique as in the archive link? (use an eponymous template for opCall?)
Jan 30 2014
parent reply "Frustrated" <c1514843 drdrb.com> writes:
BTW,

a() is replaced with a.opCall()

and you can use opDispatch on it.

an opCall is a member.

Either approach should work if you can get that archive example
to compile.
Jan 30 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 30 January 2014 at 18:11:49 UTC, Frustrated wrote:
 BTW,

 a() is replaced with a.opCall()

 and you can use opDispatch on it.

 an opCall is a member.

 Either approach should work if you can get that archive example
 to compile.
I am sure that the error is thrown before. But please show me your attempts.
Jan 30 2014
parent reply "Frustrated" <c1514843 drdrb.com> writes:
import std.stdio;

struct B
{
	template opCall(T)
	{
		void opCall(T x)
		{
			writeln(x);
		}
	}
}

template a(T)
{
	
}

void main() {
	B a;
	a(3);	// works because template parameter can be deduced from
arguments
	a.opCall!(int)(3); // same as about but explicit
	a!(int)(3); // works but calls template because a! refers to a
template
	// no way to use the above syntax to initiate an opCall on a
because it is template notation.
	// at most one might get away with a.!(int)(3) but this is
invalid
}



You'll never be able to do a!()() for the reasons give above. At
most it would have to be implemented the compiler and I doubt it
will ever happen. (for example, one could have the opExclamation
but then one has ambiguity, which is why ! was chosen to avoid in
the first place)


I think for your example, the first case works fine using
deduction.
Jan 30 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
 I think for your example, the first case works fine using
 deduction.
Sure but this is not always possible. ;) It seems that the problem occurs also with opIndex and so probably with all op* methods. See: http://forum.dlang.org/thread/bug-12043-3 https.d.puremagic.com%2Fissues%2F#post-lcegar:241ld2:241:40digitalmars.com
Jan 30 2014
parent reply "Frustrated" <c1514843 drdrb.com> writes:
On Thursday, 30 January 2014 at 21:33:09 UTC, Namespace wrote:
 I think for your example, the first case works fine using
 deduction.
Sure but this is not always possible. ;) It seems that the problem occurs also with opIndex and so probably with all op* methods. See: http://forum.dlang.org/thread/bug-12043-3 https.d.puremagic.com%2Fissues%2F#post-lcegar:241ld2:241:40digitalmars.com
Yes, because they all are implicit. It looks like you are calling a template. D could figure this out but I think it will end up having similar issues as >> has in C++. Is it an a templated op* on an object or is it template function call?
Jan 30 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 30 January 2014 at 22:34:52 UTC, Frustrated wrote:
 On Thursday, 30 January 2014 at 21:33:09 UTC, Namespace wrote:
 I think for your example, the first case works fine using
 deduction.
Sure but this is not always possible. ;) It seems that the problem occurs also with opIndex and so probably with all op* methods. See: http://forum.dlang.org/thread/bug-12043-3 https.d.puremagic.com%2Fissues%2F#post-lcegar:241ld2:241:40digitalmars.com
Yes, because they all are implicit. It looks like you are calling a template. D could figure this out but I think it will end up having similar issues as >> has in C++. Is it an a templated op* on an object or is it template function call?
Explan it please with examples. I'm convinced that D is smarter as C++ with the '>>' problem. --- class Foo { void opCall(size_t count) { } } Foo f = new Foo(); f(42); /// no template ---- ---- class Foo { void opCall(T)(size_t count) { } } Foo f = new Foo(); f!int(42); /// template ---- No ambiguity. As far as I understand you, you mean something like this: ---- import std.stdio; class Foo { void opCall(size_t count) { writeln("F()"); } } void f(T)(size_t count) { writeln("f()"); } void main() { Foo f = new Foo(); f(42); } ---- which prints correctly "F()"
Jan 30 2014
next sibling parent "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
Ask yourself this: in regards to overload resolution, when should 
template instantiation occur?
Jan 30 2014
prev sibling parent reply "Frustrated" <c1514843 drdrb.com> writes:
On Friday, 31 January 2014 at 00:29:20 UTC, Namespace wrote:
 On Thursday, 30 January 2014 at 22:34:52 UTC, Frustrated wrote:
 On Thursday, 30 January 2014 at 21:33:09 UTC, Namespace wrote:
 I think for your example, the first case works fine using
 deduction.
Sure but this is not always possible. ;) It seems that the problem occurs also with opIndex and so probably with all op* methods. See: http://forum.dlang.org/thread/bug-12043-3 https.d.puremagic.com%2Fissues%2F#post-lcegar:241ld2:241:40digitalmars.com
Yes, because they all are implicit. It looks like you are calling a template. D could figure this out but I think it will end up having similar issues as >> has in C++. Is it an a templated op* on an object or is it template function call?
Explan it please with examples. I'm convinced that D is smarter as C++ with the '>>' problem. --- class Foo { void opCall(size_t count) { } } Foo f = new Foo(); f(42); /// no template ---- ---- class Foo { void opCall(T)(size_t count) { } } Foo f = new Foo(); f!int(42); /// template ---- No ambiguity. As far as I understand you, you mean something like this: ---- import std.stdio; class Foo { void opCall(size_t count) { writeln("F()"); } } void f(T)(size_t count) { writeln("f()"); } void main() { Foo f = new Foo(); f(42); } ---- which prints correctly "F()"
no, f(42) is not a template call and f!(42) is not ambiguous because opCall is not templated. So no ambiguity here. But if you have class Foo { void opCall(T)(size_t count) { writeln("F()"); } } then do f!(42); AND had the notation you wanted to use earlier. then which f is to be called? is f!(string)(42) referring to the templates opCall? OR is f!(string)(42) calling the template(which it normally would)? The point being there can be no unambiguous way to use the template call notation with a templated opCall if the template parameter must be explicitly given. If it can be deduced then it's call looks like a normal function call and no ! is needed, and then no ambiguity. C++ had the issues where it crapped out on >>. When used in template calls, say two nested ones), one would end up with >>, which the compiler would think it was a left shift operation and not part of the template. One would always have to put a space between them to make the templates work properly. This has been recently fixed. Somewhere on the D site, Walter(I guess) explains that he chose to use ! for template call syntax because it is not used anywhere else in any ambiguous way so when you see a template call YOU know it is a template call, unambiguously. So it becomes easy to deal with semantically. So, if your notation was implemented, it would no longer be easy to know. The compiler would have to be context sensitive, which is more complex and not perfect. I doubt Walter would go for that so you'll never be able to use an explicit templated opCall... but implicit are ok.
Jan 31 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
 So, if your notation was implemented, it would no longer be easy
 to know. The compiler would have to be context sensitive, which
 is more complex and not perfect. I doubt Walter would go for 
 that
 so you'll never be able to use an explicit templated opCall...
 but implicit are ok.
I never wanted a new notation. I only want that the bug gets fixed. :)
Jan 31 2014
parent reply "Frustrated" <c1514843 drdrb.com> writes:
On Friday, 31 January 2014 at 10:31:52 UTC, Namespace wrote:
 So, if your notation was implemented, it would no longer be 
 easy
 to know. The compiler would have to be context sensitive, which
 is more complex and not perfect. I doubt Walter would go for 
 that
 so you'll never be able to use an explicit templated opCall...
 but implicit are ok.
I never wanted a new notation. I only want that the bug gets fixed. :)
Wow, that is the point! it's not a bug! You are asking for a new notation. In your post you did F f; int i = f(3,4,5); float f_ = f!float(6, 7, 8); f is an object!!! not a template, you are calling opCall on it, right? (the last line) BUT THAT SYNTAX IS FOR TEMPLATES ONLY!!! Do you not see that if I add template f(T) { T f(int x, int y, int z) { return 3.14; } } that there is no way the compiler can know what you mean now? (again, assuming your "bug" was fixed) PAY ATTENTION!!! The following is your code with the added template I gave and two lines of yours commented out! import std.stdio; struct F { T opCall(T = int)(int a, int b, int c) { return cast(T)(a * b * c); } } void main() { //F f; //int i = f(3,4,5); float f_ = f!float(6, 7, 8); } template f(T) { T f(int x, int y, int z) { return 3.14; } } NOTE TO YOURSELF!! IT COMPILES JUST FINE!!!! I didn't change a damn thing! I'm not playing tricks or anything. the float f_ line is exactly what you gave, YET I MADE IT COMPILE WITH OUT YOUR STRUCT!!! THIS MEANS IT IS AMBIGUOUS! Your struct or my template would make it work(again, assume you could actually do what you want). This means it is impossible for the compiler to know which one you meant if we uncommented the lines. The only way it would work is if one couldn't have variables and templates use the same name at the same time in the same scope.... but this already is possible and is not ambiguous. So to fix your "bug" could break the compiler in certain circumstances. will it do it in all circumstances, no. But I doubt Walter will go for it. Not only does it look like a template call(it is in the above example), it might be hard to parse and is ambiguous in some cases. Now, maybe there is a trick to make it all work using aliases and templates but that is not the point. The point is, that the is an ambiguity because you are using the EXACT same syntax for two different things. If you can't see that then I can't help you any further.
Jan 31 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Friday, 31 January 2014 at 11:42:54 UTC, Frustrated wrote:
 On Friday, 31 January 2014 at 10:31:52 UTC, Namespace wrote:
 So, if your notation was implemented, it would no longer be 
 easy
 to know. The compiler would have to be context sensitive, 
 which
 is more complex and not perfect. I doubt Walter would go for 
 that
 so you'll never be able to use an explicit templated opCall...
 but implicit are ok.
I never wanted a new notation. I only want that the bug gets fixed. :)
Wow, that is the point! it's not a bug! You are asking for a new notation. In your post you did F f; int i = f(3,4,5); float f_ = f!float(6, 7, 8); f is an object!!! not a template, you are calling opCall on it, right? (the last line) BUT THAT SYNTAX IS FOR TEMPLATES ONLY!!! Do you not see that if I add template f(T) { T f(int x, int y, int z) { return 3.14; } } that there is no way the compiler can know what you mean now? (again, assuming your "bug" was fixed) PAY ATTENTION!!! The following is your code with the added template I gave and two lines of yours commented out! import std.stdio; struct F { T opCall(T = int)(int a, int b, int c) { return cast(T)(a * b * c); } } void main() { //F f; //int i = f(3,4,5); float f_ = f!float(6, 7, 8); } template f(T) { T f(int x, int y, int z) { return 3.14; } } NOTE TO YOURSELF!! IT COMPILES JUST FINE!!!! I didn't change a damn thing! I'm not playing tricks or anything. the float f_ line is exactly what you gave, YET I MADE IT COMPILE WITH OUT YOUR STRUCT!!! THIS MEANS IT IS AMBIGUOUS! Your struct or my template would make it work(again, assume you could actually do what you want). This means it is impossible for the compiler to know which one you meant if we uncommented the lines. The only way it would work is if one couldn't have variables and templates use the same name at the same time in the same scope.... but this already is possible and is not ambiguous. So to fix your "bug" could break the compiler in certain circumstances. will it do it in all circumstances, no. But I doubt Walter will go for it. Not only does it look like a template call(it is in the above example), it might be hard to parse and is ambiguous in some cases.
Are you always so aggressive? :)
Jan 31 2014
parent "Frustrated" <c1514843 drdrb.com> writes:
 Are you always so aggressive? :)
Not always ;) Just when I feel like it....
Jan 31 2014
prev sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 30 January 2014 at 16:55:01 UTC, Meta wrote:
 On Thursday, 30 January 2014 at 15:59:28 UTC, Namespace wrote:
 Here: http://dlang.org/operatoroverloading.html#FunctionCall
 is this example:
 ----
 import std.stdio;

 struct F {
 	int opCall() {
 		return 0;
 	}
 	
 	int opCall(int x, int y, int z) {
 		return x * y * z;
 	}
 }

 void main() {
 	F f;
 	int i;

 	i = f();      // same as i = f.opCall();
 	i = f(3,4,5); // same as i = f.opCall(3,4,5);
 }
 ----

 And it works of course. But what if I want to templatize 
 opCall? How can I call it?

 ----
 import std.stdio;

 struct F {
 	T opCall(T = int)(int a, int b, int c) {
 		return cast(T)(a * b * c);
 	}
 }

 void main() {
 	F f;
 	int i = f(3,4,5);
 	float f_ = f!float(6, 7, 8);
 }
 ----

 Does not work, it fails with:
 Error: template instance f!float f is not a template 
 declaration, it is a variable
This is probably a bug. You should file it in Bugzilla.
Ok, done: https://d.puremagic.com/issues/show_bug.cgi?id=12043
Jan 30 2014