www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How do I initialize a templated constructor?

reply rempas <rempas tutanota.com> writes:
In the following struct (as an example, not real code):

```
struct TestArray(ulong element_n) {
   int[element_n] elements;

   this(string type)(ulong number) {
     pragma(msg, "The type is: " ~ typeof(type).stringof);
   }
}
```

I want to create it and be able to successfully initialize the 
template parameters
of the constructor but until now, I wasn't able to find a way to 
successfully do
that. Is there a way you guys know?  I have tried the following:

```
void main() {
   // Doesn't work
   auto val = TestArray!(10, "int")(60);

   // Doesn't work either
   auto val = TestArray!(10).TestArray!("int")(60);

   // Neither this works....
   auto val = TestArray!(10).this!("int")(60);
}
```

As with every question I make, the solution must be "betterC" 
compatible so I can use it.
Thanks a lot!
Aug 07 2022
next sibling parent reply bauss <jacobbauss gmail.com> writes:
On Monday, 8 August 2022 at 05:38:31 UTC, rempas wrote:
 In the following struct (as an example, not real code):

 ```
 struct TestArray(ulong element_n) {
   int[element_n] elements;

   this(string type)(ulong number) {
     pragma(msg, "The type is: " ~ typeof(type).stringof);
   }
 }
 ```

 I want to create it and be able to successfully initialize the 
 template parameters
 of the constructor but until now, I wasn't able to find a way 
 to successfully do
 that. Is there a way you guys know?  I have tried the following:

 ```
 void main() {
   // Doesn't work
   auto val = TestArray!(10, "int")(60);

   // Doesn't work either
   auto val = TestArray!(10).TestArray!("int")(60);

   // Neither this works....
   auto val = TestArray!(10).this!("int")(60);
 }
 ```

 As with every question I make, the solution must be "betterC" 
 compatible so I can use it.
 Thanks a lot!
``` this(string type)(ulong number) { ``` You cannot do this. Instead your type should look like this: First let's change it up a little bit. ``` struct TestArray(ulong element_n, string type) { int[element_n] elements; this(ulong number) { pragma(msg, "The type is: " ~ typeof(type).stringof); } } ``` Now the above will still not work because you do `typeof(type)` which will always yield string because type is as string and also the typeof() is not needed in this case and will actually yield an error. If it must be a string then you can do it like this: ``` struct TestArray(ulong element_n, string type) { int[element_n] elements; this(ulong number) { mixin("alias T = " ~ type ~ ";"); pragma(msg, "The type is: " ~ T.stringof); } } ``` However the ideal implementation is probably this: ``` struct TestArray(ulong element_n, T) { int[element_n] elements; this(ulong number) { pragma(msg, "The type is: " ~ T.stringof); } } ``` To instantiate it you simply do: ``` TestArray!(10, "int") val = TestArray!(10, "int")(100); ``` Or ``` TestArray!(10, int) val = TestArray!(10, int)(100); ``` I will recommend an alias to make it easier: ``` alias IntTestArray = TestArray!(10, int); ... IntTestArray val = IntTestArray(100); ```
Aug 07 2022
next sibling parent reply rempas <rempas tutanota.com> writes:
On Monday, 8 August 2022 at 06:58:42 UTC, bauss wrote:
 ```
 this(string type)(ulong number) {
 ```

 You cannot do this.

 Instead your type should look like this:

 First let's change it up a little bit.

 ```
 struct TestArray(ulong element_n, string type) {
   int[element_n] elements;

   this(ulong number) {
     pragma(msg, "The type is: " ~ typeof(type).stringof);
   }
 }
 ```

 Now the above will still not work because you do `typeof(type)` 
 which will always yield string because type is as string and 
 also the typeof() is not needed in this case and will actually 
 yield an error.

 If it must be a string then you can do it like this:

 ```
 struct TestArray(ulong element_n, string type) {
   int[element_n] elements;

   this(ulong number) {
     mixin("alias T = " ~ type ~ ";");
     pragma(msg, "The type is: " ~ T.stringof);
   }
 }
 ```

 However the ideal implementation is probably this:

 ```
 struct TestArray(ulong element_n, T) {
   int[element_n] elements;

   this(ulong number) {
     pragma(msg, "The type is: " ~ T.stringof);
   }
 }
 ```

 To instantiate it you simply do:

 ```
 TestArray!(10, "int") val = TestArray!(10, "int")(100);
 ```

 Or

 ```
 TestArray!(10, int) val = TestArray!(10, int)(100);
 ```

 I will recommend an alias to make it easier:

 ```
 alias IntTestArray = TestArray!(10, int);

 ...

 IntTestArray val = IntTestArray(100);
 ```
Thank you for all the great info! Unfortunately, while there is no problem in this example, this will not do for my real code as I need to have the argument in the constructor. Alternative, I have to change the design of the program completely....
Aug 08 2022
parent reply bauss <jacobbauss gmail.com> writes:
On Monday, 8 August 2022 at 07:37:16 UTC, rempas wrote:
 Thank you for all the great info! Unfortunately, while there is 
 no problem in this example, this will
 not do for my real code as I need to have the argument in the 
 constructor. Alternative, I have to
 change the design of the program completely....
Yeah I think the only template argument you can have for constructors are `this` which will refer to things like the class that inherited the current class etc. not sure what else, but you can't really pass anything to it yourself unfortunately. But I think if you end up with something where you need different constructors with different type arguments then you're probably designing your program in a "wrong" way to begin with.
Aug 08 2022
parent rempas <rempas tutanota.com> writes:
On Monday, 8 August 2022 at 08:27:49 UTC, bauss wrote:
 Yeah I think the only template argument you can have for 
 constructors are `this` which will refer to things like the 
 class that inherited the current class etc. not sure what else, 
 but you can't really pass anything to it yourself unfortunately.
It's fine, thanks for trying in any case!
 But I think if you end up with something where you need 
 different constructors with different type arguments then 
 you're probably designing your program in a "wrong" way to 
 begin with.
Oh, trust me! I didn't designed my program wrong in my case. At least not the way I see it!
Aug 08 2022
prev sibling parent reply Dom Disc <dominikus scherkl.de> writes:
On Monday, 8 August 2022 at 06:58:42 UTC, bauss wrote:
 On Monday, 8 August 2022 at 05:38:31 UTC, rempas wrote:
 In the following struct (as an example, not real code):

 ```
 struct TestArray(ulong element_n) {
   int[element_n] elements;

   this(string type)(ulong number) {
     pragma(msg, "The type is: " ~ typeof(type).stringof);
   }
 }
 ```
You cannot do this.
But if you only want to know the type of the parameter, you can do this: ```D struct TestArray(ulong element_n) { int[element_n] elements; this(type)(type number) { pragma(msg, "The type is: " ~ type.stringof); } } ```
Aug 08 2022
next sibling parent Dom Disc <dominikus scherkl.de> writes:
And then you can instantiate it with

```D
auto val = TestArray!10(ubyte(60)); // if you want type to be 
ubyte
```
Aug 08 2022
prev sibling parent reply rempas <rempas tutanota.com> writes:
On Monday, 8 August 2022 at 11:03:21 UTC, Dom Disc wrote:
 But if you only want to know the type of the parameter, you can 
 do this:

 ```D
 struct TestArray(ulong element_n) {
   int[element_n] elements;

   this(type)(type number)
   {
     pragma(msg, "The type is: " ~ type.stringof);
   }
 }
 ```
Unfortunately this will not do as well....
Aug 08 2022
parent zjh <fqbqrr 163.com> writes:
On Monday, 8 August 2022 at 12:26:50 UTC, rempas wrote:
 On Monday, 8 August 2022 at 11:03:21 UTC, Dom Disc wrote:
You should first describe what you want to do clearly.
Aug 08 2022
prev sibling next sibling parent WebFreak001 <d.forum webfreak.org> writes:
On Monday, 8 August 2022 at 05:38:31 UTC, rempas wrote:
 In the following struct (as an example, not real code):

 ```
 struct TestArray(ulong element_n) {
   int[element_n] elements;

   this(string type)(ulong number) {
     pragma(msg, "The type is: " ~ typeof(type).stringof);
   }
 }
 ```

 I want to create it and be able to successfully initialize the 
 template parameters
 of the constructor but until now, I wasn't able to find a way 
 to successfully do
 that. Is there a way you guys know?  I have tried the following:

 ```
 void main() {
   // Doesn't work
   auto val = TestArray!(10, "int")(60);

   // Doesn't work either
   auto val = TestArray!(10).TestArray!("int")(60);

   // Neither this works....
   auto val = TestArray!(10).this!("int")(60);
 }
 ```

 As with every question I make, the solution must be "betterC" 
 compatible so I can use it.
 Thanks a lot!
I would move the constructor out of the struct into a helper function, either global or as a static member: ```d TestArray!n testArray(ulong n, string type)(ulong number) { TestArray!n ret; pragma(msg, "The type is: " ~ typeof(type).stringof); ret.something = something; // do your constructor logic here return ret; } ``` which you can then use: ```d auto t = testArray!(10, "int")(60); ``` As the template parameter being part of the constructor would only change the constructor (and can't change anything like types outside the ctor) it doesn't have any limitations and if you define it in the same module as the struct you can also access the private members.
Aug 08 2022
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/7/22 22:38, rempas wrote:

 I want to create it and be able to successfully initialize the template
 parameters
 of the constructor but until now, I wasn't able to find a way to
 successfully do
 that.
The following method uses a convenience function but it's not really needed: import std.stdio; struct TestArray(ulong element_n, string type) { int[element_n] elements; mixin(type) member; pragma(msg, "The type is: ", typeof(member)); this(ulong number) { writeln("Constructing with ", number); } } auto makeTestArray(ulong element_n, string type)(ulong number) { return TestArray!(element_n, type)(number); } void main() { auto ta = makeTestArray!(10, "int")(60); } Ali
Aug 08 2022
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/8/22 1:38 AM, rempas wrote:
 In the following struct (as an example, not real code):
 
 ```
 struct TestArray(ulong element_n) {
    int[element_n] elements;
 
    this(string type)(ulong number) {
      pragma(msg, "The type is: " ~ typeof(type).stringof);
    }
 }
 ```
 
 I want to create it and be able to successfully initialize the template 
 parameters
 of the constructor but until now, I wasn't able to find a way to 
 successfully do
 that. Is there a way you guys know?  I have tried the following:
 
 ```
 void main() {
    // Doesn't work
    auto val = TestArray!(10, "int")(60);
 
    // Doesn't work either
    auto val = TestArray!(10).TestArray!("int")(60);
 
    // Neither this works....
    auto val = TestArray!(10).this!("int")(60);
 }
 ```
 
 As with every question I make, the solution must be "betterC" compatible 
 so I can use it.
 Thanks a lot!
You cannot explicitly specify template parameters for constructors. The only true solution is to use a factory function: ```d TestArray!T testarray(string s, T)(T val) { ... // code that depends on s here return TestArray!T(...) // call ctor here. } ``` -Steve
Aug 08 2022
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/8/22 9:36 AM, Steven Schveighoffer wrote:
 On 8/8/22 1:38 AM, rempas wrote:
 In the following struct (as an example, not real code):

 ```
 struct TestArray(ulong element_n) {
    int[element_n] elements;

    this(string type)(ulong number) {
      pragma(msg, "The type is: " ~ typeof(type).stringof);
    }
 }
 ```

 I want to create it and be able to successfully initialize the 
 template parameters
 of the constructor but until now, I wasn't able to find a way to 
 successfully do
 that. Is there a way you guys know?  I have tried the following:

 ```
 void main() {
    // Doesn't work
    auto val = TestArray!(10, "int")(60);

    // Doesn't work either
    auto val = TestArray!(10).TestArray!("int")(60);

    // Neither this works....
    auto val = TestArray!(10).this!("int")(60);
 }
 ```

 As with every question I make, the solution must be "betterC" 
 compatible so I can use it.
 Thanks a lot!
You cannot explicitly specify template parameters for constructors. The only true solution is to use a factory function: ```d TestArray!T testarray(string s, T)(T val) {    ... // code that depends on s here    return TestArray!T(...) // call ctor here. } ```
Just thought of another possibility: ```d struct StringAnnotated(string s, T) { T val; } StringAnnotated!(s, T) annotate(string s, T)(T val) { return StringAnnotated!(s, T)(val); } struct TestArray(ulong element_n) { ... this(T)(T val) if (isInstanceOf!(StringAnnotated, T)) { ... } } // use like TestArray!10(60.annotate!"int"); ``` -Steve
Aug 08 2022
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
Here is another one that uses nested templates:

import std.stdio;

template TestArray(ulong element_n) {
   struct TestArrayImpl(Type) {
     int[element_n] elements;

     this(ulong number) {
       pragma(msg, "The type is: ", Type);
       writeln("Constructing with ", number);
     }
   }

   auto makeFor(string s)(ulong number) {
     return TestArrayImpl!(mixin(s))(number);
   }
}

void main() {
   auto ta = TestArray!10.makeFor!"int"(60);
}

Ali
Aug 08 2022
prev sibling parent rempas <rempas tutanota.com> writes:
Thank you all for the info! I'll try to find another way to do it 
as it is not possible
to match the exact behavior I want! Have a great day everyone!
Aug 08 2022