Operator Overloading and boilerplate code
Ali Çehreli
acehreli at yahoo.com
Tue Jul 5 09:05:13 PDT 2011
On Tue, 05 Jul 2011 16:20:44 +0200, Loopback wrote:
> On 2011-07-05 03:11, Ali Çehreli wrote:
>> struct S
>> {
>> this(T)(double d)
>> {}
>> }
>>
>> void main()
>> {
>> auto o = S(1.5);
>> }
>>
>> Error: template deneme.S.__ctor(T) does not match any function template
>> declaration
>> Error: template deneme.S.__ctor(T) cannot deduce template function from
>> argument types !()(double)
>>
>> The compiler is right: What should T be there? int? string? MyClass?
>>
>> I've realized again that I don't know how to specify the template
>> parameter for the constructor. The following attempt fails as the
>> compiler thinks S itself is a template:
>>
>> auto o = S!string(1.5);
>>
>> Error: template instance S is not a template declaration, it is a
>> struct
>>
>> And if I try to be smart after the error message, this seg faults the
>> compiler:
>>
>> auto o = S.__ctor!string(1.5);
>>
>> Ali
> Hmm... Interesting. Thank you for clarifying and explaining that!
>
> I guess supplying T to the constructor when the parameters are already
> known to avoid compiler errors is not a solution then. Seems to me as if
> its only aggravates things.
>
> Though is there no solution nor any workarounds for this problem? I've
> attempted to use two different types of constructors and both appeared
> to be very limited, and I do not believe that this is the case.
I don't want to look like brushing off the problem but having many
constructors make the code complicated. For example, it may be confusing
which constructor gets called here:
auto d = DVECTOR2(1.5);
Are we setting just x or both x and y? Especially when we know that
DVECTOR2 is a struct and that structs have this feature of assigning
default values to the trailing unspecified members (at least in some
cases), I think a factory function would be better in this case:
auto d = square_DVECTOR2(1.5);
Now we know that both x and y will be 1.5.
Same can be said for some of the other constructors. It is not difficult
at all for the caller to give us what we want; and it is clearer:
D3DXVECTOR2 d3;
// ...
auto d = DVECTOR2(d3.tupleof);
(I think this is in line with Kevlin Henney's "Parameterize from Above"
guideline/pattern/idiom/etc. :))
> If you use a generic constructor is there no possible way to use it in
> cases where immutable and const is involved? Or is there a page that I
> have missed perhaps?
D2 has changed the meaning of inout to mean something like "templatize
just the mutable/const/immutable qualification of the parameter" but it
is not implemented fully yet. Look at "Inout Functions" on the Functions
spec:
http://d-programming-language.org/function.html
> struct DVECTOR2
> {
> // Controls that the parameter is a valid type template Accepts
(T) {
> enum Accepts = is(T == DVECTOR2) || is(T == float) || is(T ==
> D3DXVECTOR2) || is(T == POINT); }
>
> // Whether the parameter is a float or not
> template isScalar(T) { enum isScalar = is(T == float); }
>
> // The Variables
> float x = 0f;
> float y = 0f;
>
> // Default Constructor
> this()(float x, float y)
> {
> this.x = x;
> this.y = y;
> }
>
> // Float Constructor
> this()(float xy) { this(xy, xy); }
>
> // Implement D3DXVECTOR2 and POINT support
> this(T)(T arg) if (Accepts!T
> && !isScalar!T) { this(arg.tupleof); }
Ali
More information about the Digitalmars-d-learn
mailing list