If I want a template constraint that requires that some alias/member is an lvalue, I have to do something very complex (courtesy of Meta from the forums):
template yieldsLval(Aggregate, alias member)
{
import std.traits: ReturnType;
import std.functional: FunctionTypeOf;
import std.typetuple: staticIndexOf;
static if (isSomeFunction!member)
{
enum yieldsLval = __traits(compiles,
{
alias Ftype = FunctionTypeOf!member;
void takesLval(ref ReturnType!Ftype) {}
takesLval(Ftype());
});
}
//It's a member variable
else static if (staticIndexOf!(member.stringof, FieldNameTuple!Aggregate) > -1)
enum yieldsLval = true;
else
static assert(false, "Symbol " ~ member.stringof ~ " is not a member function or variable of " ~ Aggregate.stringof);
}
struct S
{
int x;
ref int y() { return x; }
int z() { return 1; }
enum f = 0;
}
void main()
{
static assert(yieldsLval!(S, S.y));
static assert(yieldsLval!(S, S.x));
static assert(!yieldsLval!(S, S.z));
static assert(!__traits(compiles, yieldsLval!(S, S.f)));
}
I'm assuming the compiler has this information pretty handy, since it complains about using rvalues where lvalues are required all the time.
Can we get a __traits call to get this info out of the compiler?
For reference: https://forum.dlang.org/post/[email protected]
Comment #1 by stanislav.blinov — 2020-06-13T12:07:56Z
Stumbled on this via a forum thread (four years later, yay), and honestly I find this request rather strange.
There is a trait that provides such information for functions - the getFunctionAttributes. It already existed at the time of this issue report, and is even touched upon in aforementioned forum thread, albeit in Phobos disguise.
However, the "some alias/member" may be (among others):
- an overloaded function
- a function template with auto ref parameters
In both of those cases, a __trait won't be able to provide the information required, since symbol alone is simply insufficient. Overloads would need to be tested one by one, carefully matching arguments; templates would have to be instantiated, again carefully matching arguments. Consider:
struct S
{
string x;
// NOTE: y is overloaded
void y() {}
ref y(return ref int z) { return z; }
float y(float z) { return z; }
// whether it returns rvalue or lvalue depends on what is passed
auto ref tpl(Args...)(auto ref Args args) {
static if (args.length)
return args[0];
}
}
static assert(__traits(hypotheticalIsLvalue, S.y)); // which `y` ???
static assert(__traits(hypotheticalIsLvalue, S.tpl)); // ???
Comment #2 by schveiguy — 2020-06-15T12:11:37Z
Yeah, I think this was a suggestion from someone because the code he used to do the same thing was really complex.
But later, someone posted a much simpler solution (just try passing the result into a ref lambda). I don't really need this. I should have closed it immediately. Thanks.