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