www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template specialisation for range of types

reply data pulverizer <data.pulverizer gmail.com> writes:
Hello all,

I am attempting to write templates for differently qualified 
types using specialisations. Below is an example for const and 
non-const outlining my approach:


``````````````````````````
import std.stdio : writeln;
import std.traits : ConstOf;

auto max(T)(T x, T y)
{
	writeln("General template");
	return x > y ? x : y;
}


auto max(T: ConstOf!U, U)(T* x, T* y)
{
	writeln("Const template");
	return *x > *y ? x : y;
}


void main(){
	const double p = 2.4, q = 3;
	writeln(max(&p, &q));
}
``````````````````````````

I get this output:

General template
7FFE5B3759A8


In this case would like to use the ConstOf specialisation instead 
of the default implementation for the inputs which are const.

Thanks for you answers in advance
Mar 12
next sibling parent Jerry <Kickupx gmail.com> writes:
On Sunday, 12 March 2017 at 18:49:22 UTC, data pulverizer wrote:
 Hello all,

 I am attempting to write templates for differently qualified 
 types using specialisations. Below is an example for const and 
 non-const outlining my approach:


 ``````````````````````````
 import std.stdio : writeln;
 import std.traits : ConstOf;

 auto max(T)(T x, T y)
 {
 	writeln("General template");
 	return x > y ? x : y;
 }


 auto max(T: ConstOf!U, U)(T* x, T* y)
 {
 	writeln("Const template");
 	return *x > *y ? x : y;
 }


 void main(){
 	const double p = 2.4, q = 3;
 	writeln(max(&p, &q));
 }
 ``````````````````````````

 I get this output:

 General template
 7FFE5B3759A8


 In this case would like to use the ConstOf specialisation 
 instead of the default implementation for the inputs which are 
 const.

 Thanks for you answers in advance
Wouldn't just putting const infront work?
Mar 12
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
data pulverizer wrote:

 In this case would like to use the ConstOf specialisation instead of the 
 default implementation for the inputs which are const.
actually, second template is uninstantiable at all. you want to do type deconstruction at instantiation, and that doesn't work. i.e. what your code wants to do (as it is written) is to have `T` in second template to be equal to `double`. you cannot deconstruct the type like that in template. what you *can* do, though, is this: auto max(T)(const(T)* x, const(T)* y) this way it will select your second template.
Mar 12
parent reply data pulverizer <data.pulverizer gmail.com> writes:
On Sunday, 12 March 2017 at 19:32:37 UTC, ketmar wrote:
 data pulverizer wrote:

 In this case would like to use the ConstOf specialisation 
 instead of the default implementation for the inputs which are 
 const.
actually, second template is uninstantiable at all. you want to do type deconstruction at instantiation, and that doesn't work. i.e. what your code wants to do (as it is written) is to have `T` in second template to be equal to `double`. you cannot deconstruct the type like that in template. what you *can* do, though, is this: auto max(T)(const(T)* x, const(T)* y) this way it will select your second template.
If I change the implementation of the second template to your above declaration, I get the error: max.max called with argument types (const(double)*, const(double)*) matches both: max.d(34): max.max!(const(double)*).max(const(double)* x, const(double)* y) and: max.d(42): max.max!double.max(const(double)* x, const(double)* y) I need at least those two implementation for the different cases, a general "default", and for specified types and type qualifications.
Mar 12
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
data pulverizer wrote:

 If I change the implementation of the second template to your above 
 declaration, I get the error:

 max.max called with argument types (const(double)*, const(double)*) 
 matches both:
 max.d(34):     max.max!(const(double)*).max(const(double)* x, 
 const(double)* y)
 and:
 max.d(42):     max.max!double.max(const(double)* x, const(double)* y)

 I need at least those two implementation for the different cases, a 
 general "default", and for specified types and type qualifications.
'cause your templates are for different types, so they both matches. i wrote only about type deconstruction. the following will work: import std.stdio : writeln; import std.traits : Unqual; auto max(T)(T* x, T* y) if (is(T == Unqual!T)) { writeln("General template"); return *x > *y ? x : y; } auto max(T)(T* x, T* y) if (is(T == const)) { writeln("Const template"); return *x > *y ? x : y; } void main () { const double p = 2.4, q = 3; writeln(max(&p, &q)); } note the change in the first template.
Mar 12
prev sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
data pulverizer wrote:

 I need at least those two implementation for the different cases, a 
 general "default", and for specified types and type qualifications.
p.s.: if you want that to work with both pointers and non-pointers, you have to add more constraints, to remove further conflicts.
Mar 12
prev sibling parent reply Meta <jared771 gmail.com> writes:
On Sunday, 12 March 2017 at 18:49:22 UTC, data pulverizer wrote:
 Hello all,

 I am attempting to write templates for differently qualified 
 types using specialisations. Below is an example for const and 
 non-const outlining my approach:


 ``````````````````````````
 import std.stdio : writeln;
 import std.traits : ConstOf;

 auto max(T)(T x, T y)
 {
 	writeln("General template");
 	return x > y ? x : y;
 }


 auto max(T: ConstOf!U, U)(T* x, T* y)
 {
 	writeln("Const template");
 	return *x > *y ? x : y;
 }


 void main(){
 	const double p = 2.4, q = 3;
 	writeln(max(&p, &q));
 }
 ``````````````````````````

 I get this output:

 General template
 7FFE5B3759A8


 In this case would like to use the ConstOf specialisation 
 instead of the default implementation for the inputs which are 
 const.

 Thanks for you answers in advance
You need to make one little change for this to work: import std.stdio : writeln; import std.traits : ConstOf; auto max(T)(T x, T y) { writeln("General template"); return x > y ? x : y; } auto max(T: const U, U)(T* x, T* y) <----- Changed `ConstOf!U` to `const U` { writeln("Const template"); return *x > *y ? x : y; } void main(){ const double p = 2.4, q = 3; writeln(max(&p, &q)); //Prints "Const template" } The reason this doesn't work is when you use ConstOf!U, it's not looking for a `const U`, it's looking for the type `ConstOf!U`. I'm not sure if this is a bug or not... Anyway, this will also work if we change the following: void main(){ ConstOf!double p = 2.4, q = 3; <----- Changed `const double` to `ConstOf!double` writeln(max(&p, &q)); //Prints "Const template" }
Mar 12
next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
Meta wrote:

 The reason this doesn't work is when you use ConstOf!U, it's not looking 
 for a `const U`, it's looking for the type `ConstOf!U`. I'm not sure if 
 this is a bug or not...
no, not a bug. this is the way type deconstruction works: it checks if your type was constructed with a given template.
Mar 12
parent reply Meta <jared771 gmail.com> writes:
On Sunday, 12 March 2017 at 20:22:33 UTC, ketmar wrote:
 Meta wrote:

 The reason this doesn't work is when you use ConstOf!U, it's 
 not looking for a `const U`, it's looking for the type 
 `ConstOf!U`. I'm not sure if this is a bug or not...
no, not a bug. this is the way type deconstruction works: it checks if your type was constructed with a given template.
Yeah, it seems to be checking the pattern rather than the type. However, ConstOf!T is just an alias for const(T), but the alias does not seem to be "unwrapped", even though they are supposed to be transparent.
Mar 12
parent ketmar <ketmar ketmar.no-ip.org> writes:
Meta wrote:

 On Sunday, 12 March 2017 at 20:22:33 UTC, ketmar wrote:
 Meta wrote:

 The reason this doesn't work is when you use ConstOf!U, it's not 
 looking for a `const U`, it's looking for the type `ConstOf!U`. I'm not 
 sure if this is a bug or not...
no, not a bug. this is the way type deconstruction works: it checks if your type was constructed with a given template.
Yeah, it seems to be checking the pattern rather than the type. However, ConstOf!T is just an alias for const(T), but the alias does not seem to be "unwrapped", even though they are supposed to be transparent.
yeah. "eponymous template" trick.
Mar 12
prev sibling next sibling parent data pulverizer <data.pulverizer gmail.com> writes:
On Sunday, 12 March 2017 at 20:15:43 UTC, Meta wrote:
 import std.stdio : writeln;
 import std.traits : ConstOf;

 auto max(T)(T x, T y)
 {
 	writeln("General template");
 	return x > y ? x : y;
 }


 auto max(T: const U, U)(T* x, T* y) <----- Changed `ConstOf!U` 
 to `const U`
 {
 	writeln("Const template");
 	return *x > *y ? x : y;
 }


 void main(){
 	const double p = 2.4, q = 3;
 	writeln(max(&p, &q)); //Prints "Const template"
 }
This is great Meta, thanks very much! I was trying to avoid using template constraints because the more cases you add, the more complicated the constraints get.
Mar 12
prev sibling parent reply data pulverizer <data.pulverizer gmail.com> writes:
On Sunday, 12 March 2017 at 20:15:43 UTC, Meta wrote:
 auto max(T: const U, U)(T* x, T* y) <----- Changed `ConstOf!U` 
 to `const U`
 {
 	writeln("Const template");
 	return *x > *y ? x : y;
 }
How detailed can I be about the template specialisation? From example in the book "C++ the complete guide" we can have: /* pointer const reference */ template<typename T> inline T* const& max(T* const& a, T* const&b) { return a* < b* ? b : a; } /* const reference const pointer */ template<typename T> inline T const* const& max(T* const* const& a, T* const* const& b) { ...; } What would be the equivalent in D?
Mar 12
parent Meta <jared771 gmail.com> writes:
On Sunday, 12 March 2017 at 21:12:13 UTC, data pulverizer wrote:
 On Sunday, 12 March 2017 at 20:15:43 UTC, Meta wrote:
 auto max(T: const U, U)(T* x, T* y) <----- Changed `ConstOf!U` 
 to `const U`
 {
 	writeln("Const template");
 	return *x > *y ? x : y;
 }
How detailed can I be about the template specialisation? From example in the book "C++ the complete guide" we can have: /* pointer const reference */ template<typename T> inline T* const& max(T* const& a, T* const&b) { return a* < b* ? b : a; } /* const reference const pointer */ template<typename T> inline T const* const& max(T* const* const& a, T* const* const& b) { ...; } What would be the equivalent in D?
Unfortunately this is impossible in D as const is transitive. The best you can do is try to emulate it using wrapper types. I'd start by taking a look at std.experimental.typecons.Final, which implements C++-style head (logical) constness.
Mar 12