Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
April 26, 2018 Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
The following should depict what I'm trying to achieve: ``` import std.stdio; enum menum { A, B, C } void main() { foo(menum.B); } void foo(menum e) { // Not possible!!!! // run time variable 'e' in conjunction with template 'Temp' writeln(Temp!(GetMenum(e))); } static int i = 0; template Temp(menum e) { // ... do stuff shared static this() { static if (e == menum.A) i = 1; } import std.meta : Alias; alias Temp = Alias!i; } // Trying to return a compile-time variable with a function... Not like this... // I don't see a way to pass in the run-time variable without a function.. template GetMenum() { menum GetMenum(menum e) { import std.traits : EnumMembers; static foreach(mem; EnumMembers!menum) if (mem == e) return mem; return menum.A; } } ``` yields: Error: variable e cannot be read at compilte time However, if I replace foo with ``` void foo(menum e) { import std.traits : EnumMembers; static foreach(mem; EnumMembers!menum) if (mem == e) writeln(Temp!(GetMenum(mem))); } ``` it works.. Is it possible to use a template to place the "static foreach" looping to find the correct enum value into? Like I am trying in the initial "draft" GetMenum? |
April 26, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On Thursday, 26 April 2018 at 16:10:16 UTC, Timoses wrote:
> Is it possible to use a template to place the "static foreach" looping to find the correct enum value into? Like I am trying in the initial "draft" GetMenum?
As the compiler says, the value of `e` is not known at compile-time. In order to correctly instantiate the template with that value, all possible instantiations must be instantiated, and the correct one chosen by a static foreach, just like you do.
The only step you're missing is the template needs to be instantiated inside the static foreach, like this:
auto instantiateWith(alias Fn, T)(T x)
if (is(T == enum))
{
import std.traits : EnumMembers;
switch (x)
{
static foreach (e; EnumMembers!T)
case e:
return Fn!e;
default:
assert(false);
}
}
enum menum { A, B, C }
template Temp(menum m)
{
enum Temp = m.stringof;
}
unittest {
menum m = menum.A;
import std.stdio;
assert(instantiateWith!Temp(m) == Temp!(menum.A));
m = menum.B;
assert(instantiateWith!Temp(m) == Temp!(menum.B));
m = menum.C;
assert(instantiateWith!Temp(m) == Temp!(menum.C));
}
--
Simen
|
April 27, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Thursday, 26 April 2018 at 16:46:11 UTC, Simen Kjærås wrote: > The only step you're missing is the template needs to be instantiated inside the static foreach, like this: > > auto instantiateWith(alias Fn, T)(T x) > if (is(T == enum)) > { > import std.traits : EnumMembers; > switch (x) > { > static foreach (e; EnumMembers!T) > case e: > return Fn!e; > default: > assert(false); > } > } > > enum menum { A, B, C } > > template Temp(menum m) > { > enum Temp = m.stringof; > } Ah thanks!! I struggled a bit with finding out how to actually it in my use case. I just didn't see the pattern: ``` instantiateWith!<ANY-Template-That-should-be-instantiated-with-run-time-Var>(<run-time-var>) ``` Thank you! |
April 27, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | Bumped across another problem : / ``` import std.stdio; enum menum { A, B, C } void main() { foo(menum.A); } void foo(menum e) { writeln(instantiateWith!Temp(e)); } auto instantiateWith(alias Fn, T)(T x) if (is(T == enum)) { switch (x) { import std.traits : EnumMembers; static foreach (e; EnumMembers!T) case e: return Fn!e; default: assert(false); } } template Temp(menum e) { struct TempStruct { uint i; }; TempStruct Temp; shared static this() { static if (e == menum.A) Temp.i = 3; } } ``` now returns: source\app.d(25,17): Error: mismatched function return type inference of `TempStruct` and `TempStruct` source\app.d(12,33): Error: template instance `app.instantiateWith!(Temp, menum)` error instantiating dmd failed with exit code 1. It's the same return type... so why the error? |
April 27, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On Friday, 27 April 2018 at 13:27:45 UTC, Timoses wrote:
> Bumped across another problem : /
>
> ```
> import std.stdio;
>
> enum menum { A, B, C }
>
> void main()
> {
> foo(menum.A);
> }
>
> void foo(menum e)
> {
> writeln(instantiateWith!Temp(e));
> }
>
> auto instantiateWith(alias Fn, T)(T x)
> if (is(T == enum))
> {
> switch (x)
> {
> import std.traits : EnumMembers;
> static foreach (e; EnumMembers!T)
> case e:
> return Fn!e;
> default:
> assert(false);
> }
> }
>
> template Temp(menum e)
> {
> struct TempStruct { uint i; };
> TempStruct Temp;
>
> shared static this()
> {
> static if (e == menum.A)
> Temp.i = 3;
> }
>
> }
> ```
>
> now returns:
> source\app.d(25,17): Error: mismatched function return type inference of `TempStruct` and `TempStruct`
> source\app.d(12,33): Error: template instance `app.instantiateWith!(Temp, menum)` error instantiating
> dmd failed with exit code 1.
>
> It's the same return type... so why the error?
That's an unfortunate error message. The problem is TempStruct is defined inside the Temp template. In the same way that struct Foo(T) {} is different for Foo!int and Foo!string, TempStruct is a different type for Temp!(menum.A) and Temp!(menum.B).
The solution is to move TempStruct outside the template:
struct TempStruct { uint i; }
template Temp(menum e)
{
TempStruct Temp;
shared static this()
{
static if (e == menum.A)
Temp.i = 3;
}
}
--
Simen
|
April 27, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Friday, 27 April 2018 at 13:39:22 UTC, Simen Kjærås wrote:
> That's an unfortunate error message. The problem is TempStruct is defined inside the Temp template. In the same way that struct Foo(T) {} is different for Foo!int and Foo!string, TempStruct is a different type for Temp!(menum.A) and Temp!(menum.B).
>
> The solution is to move TempStruct outside the template:
>
> struct TempStruct { uint i; }
>
> template Temp(menum e)
> {
> TempStruct Temp;
> shared static this()
> {
> static if (e == menum.A)
> Temp.i = 3;
> }
> }
>
> --
> Simen
Ty.
I figured that's the reason. I still can't quite get my head around "Why?" though.
`instantiateWith` gets called in three variations (menum.A, menum.B and menum.C). This causes instantiateWith to return TempStruct for each case of Temp...
However, I was under the impression that a templated function will exist multiple (in this case 3) times, so the return type should be allowed to be different?!
|
April 27, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On Friday, 27 April 2018 at 13:43:47 UTC, Timoses wrote: > > `instantiateWith` gets called in three variations (menum.A, menum.B and menum.C). This causes instantiateWith to return TempStruct for each case of Temp... > > However, I was under the impression that a templated function will exist multiple (in this case 3) times, so the return type should be allowed to be different?! I think, because the enum value is a runtime parameter for instantiateWith, only a single variation of it exists. And this cannot have different return types. So... "alias Fn" and "T" stay the same. The value of x varies. https://run.dlang.io/is/jX4Ybh states the same. |
April 28, 2018 Re: Template to retrieve compile-time enum member from run-time enum member? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On Friday, 27 April 2018 at 14:33:36 UTC, Alex wrote:
> On Friday, 27 April 2018 at 13:43:47 UTC, Timoses wrote:
>>
>> `instantiateWith` gets called in three variations (menum.A, menum.B and menum.C). This causes instantiateWith to return TempStruct for each case of Temp...
>>
>> However, I was under the impression that a templated function will exist multiple (in this case 3) times, so the return type should be allowed to be different?!
>
> I think, because the enum value is a runtime parameter for instantiateWith, only a single variation of it exists. And this cannot have different return types.
> So... "alias Fn" and "T" stay the same. The value of x varies.
>
> https://run.dlang.io/is/jX4Ybh
> states the same.
Ah yes, thanks. I see it now.
|
Copyright © 1999-2021 by the D Language Foundation