strange CFTE issue
ag0aep6g via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Apr 9 09:44:41 PDT 2017
On 04/09/2017 04:36 PM, Boris-Barboris wrote:
> Hello, I have a similar problem. For the life of me I can't make CTFE
> work while manipulating collections. Source:
This post is only loosely related to the thread. Generally, please make
a new thread for a new problem.
> import std.meta;
> import std.traits;
>
> template isFunctionField(OwnerType, string field_name)
> {
> enum isFunctionField =
> isFunction(mixin(OwnerType.stringof ~ "." ~ field_name));
Aside: You forgot an exclamation mark here. isFunction is a template,
not a function.
> }
>
> string[] sfilter(T)(string[] fields)
> {
> string[] result;
> foreach (f; fields)
> {
> enum isfunc = isFunctionField!(T, f);
> // variable f cannot be read at compile time.
> // Even when I change isFunctionField from template to function that
> returns
> // bool and takes "string field_name".
> if (isfunc)
> result ~= f;
> }
> return result;
> }
>
> string[] TypeFields(T)() pure
> {
> enum field_names = [__traits(allMembers, T)];
> pragma(msg, typeof(field_names)); // prints string[]
> pragma(msg, field_names); // prints correct member names
> enum filtered = sfilter!(T)(field_names);
> return filtered;
> }
>
> //then I call it by:
> enum fields = TypeFields!(SomeStruct)();
>
> I can get string array of class members allright. Whenever I try to do
> any logic with it, I fail. I get that "enum field_names = " is not
> lvalue.
As far as I see, lvalue vs rvalue doesn't matter here. It's compile-time
constant vs variable. Or maybe "static value" vs "dynamic value".
> How should I pass it to sfilter?
Via a template parameter. Function parameters are never considered
static values (or compile-time constants), even during CTFE. It's
important to understand and to keep in mind that CTFE follows the exact
same rules as normal run-time evaluation (plus some more restrictions
that apply only to CTFE). You can't define an enum with true run-time
data, so you can't define it with a variable in CTFE either.
You can make `fields` a template sequence parameter [1]:
----
string[] sfilter(T, fields ...)()
{
/* ... body as you have it ... */
}
----
Or you can make it a template value parameter [2] with type `string[]`:
----
string[] sfilter(T, string[] fields)()
{
string[] result;
foreach (f; aliasSeqOf!fields)
{
/* ... loop body as you have it ... */
}
return result;
}
----
Both times, the `foreach` operates on a compile-time list [3] (aka alias
sequence aka AliasSeq). This is a special case of `foreach` dubbed
"static foreach". It means that the loop variable `f` is a static value.
It can be passed as a template argument.
As an alternative to the "static foreach", you could use recursion. And
then you could make it just a template instead of a function template.
CTFE wouldn't be involved. That's how std.meta.Filter [4] works. You can
use it instead of writing your own filter function/template:
----
enum field_names = __traits(allMembers, T);
enum pred(string field_name) = isFunctionField!(T, field_name);
enum filtered = [Filter!(pred, field_names)];
----
> When I change foreach loop into
> for loop, I can't index "string[] fields" array since "variable fields
> cannot be read at compile time".
Unlike `foreach`, `for` does not have a "static for" special case. The
loop variable of a `for` loop is always dynamic, never static. You can't
ever use it in a context that needs a static value.
> Should I pass field_names string array as some other type, AliasSeq or
> something?
Aside: AliasSeq is not a type.
> The thing is, on some level inside TypeFields, I will need to mutate
> array, I can't stick to tuples.
It's not obvious to me why this rules out compile-time lists (aka
tuples). Note that you can convert both ways between a compile-time list
(aka tuple) and an enum array. aliasSeqOf goes one way, wrapping in
square brackets goes the other.
> I tried declaring array parameters
> immutable, but CTFE forbids casting from mutable into immutable. I'm
> kinda out of ideas.
I suppose you tried `immutable` to tell the compiler that the values are
constant? But `immutable` doesn't mean "compile-time constant".
Dynamically computed values can be immutable. Function parameters are
never usable in static contextsZ.
[1] https://dlang.org/spec/template.html#variadic-templates
[2] https://dlang.org/spec/template.html#template_value_parameter
[3] https://dlang.org/ctarguments.html
More information about the Digitalmars-d-learn
mailing list