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

Reply via email to