digitalmars.D.learn - Introduction to traits (and __traits)
- Joseph Rushton Wakeling (22/22) Aug 30 2013 Hello all,
- Benjamin Thaut (10/34) Aug 30 2013 You need to put it into a static if, otherwise the compiler will
- Joseph Rushton Wakeling (16/25) Aug 30 2013 Ahh, right, thanks. :-)
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (4/30) Aug 30 2013 How about allSatisfy:
- Joseph Rushton Wakeling (46/48) Aug 30 2013 I'll have a look at that, thanks :-)
- bearophile (9/22) Aug 30 2013 Perhaps can shorten that code writing a hasMembers helper (and I
- H. S. Teoh (27/45) Aug 30 2013 [...]
- Joseph Rushton Wakeling (2/4) Aug 30 2013 Nice thought, I might look into that at some point. :-)
Hello all,
I find myself wanting to write for the first time one of these isSomething(T)
or
hasSomething(T) templates that perform compile-time checks, so I was hoping
people could give me some good general advice on traits.
The goal here is to be able to confirm (i) type T has certain members and (ii)
they have certain properties. (This is for my graph library, Dgraph.)
So, to start off with, I thought I'd try starting with,
template isGraph(G)
{
isGraph = __traits(hasMember, G, "directed") &&
isBoolean!(typeof(G.directed));
}
... which I'd assumed would cover the case where G does not have a member
"directed". But in fact if I pass it a struct that does not have the entity
.directed defined therein, it will return an error: "no property 'directed'
for
type ..."
So, can someone give me a good idea of how to go about writing such a
compile-time template that checks (i) for the existence of certain
methods/functions/members and (ii) confirms their characteristics, such as
their
return values or arguments?
Thanks & best wishes,
-- Joe
Aug 30 2013
Am 30.08.2013 21:36, schrieb Joseph Rushton Wakeling:
Hello all,
I find myself wanting to write for the first time one of these
isSomething(T) or hasSomething(T) templates that perform compile-time
checks, so I was hoping people could give me some good general advice on
traits.
The goal here is to be able to confirm (i) type T has certain members
and (ii) they have certain properties. (This is for my graph library,
Dgraph.)
So, to start off with, I thought I'd try starting with,
template isGraph(G)
{
isGraph = __traits(hasMember, G, "directed") &&
isBoolean!(typeof(G.directed));
}
... which I'd assumed would cover the case where G does not have a
member "directed". But in fact if I pass it a struct that does not have
the entity .directed defined therein, it will return an error: "no
property 'directed' for type ..."
So, can someone give me a good idea of how to go about writing such a
compile-time template that checks (i) for the existence of certain
methods/functions/members and (ii) confirms their characteristics, such
as their return values or arguments?
Thanks & best wishes,
-- Joe
You need to put it into a static if, otherwise the compiler will
continue semantic checks on the second part of the expression. E.g.
template isGraph(G)
{
static if(__traits(hasMember, G, "directed"))
enum bool isGraph = isBoolean!(typeof(G.directed));
else
enum bool isGraph = false;
}
Aug 30 2013
On 30/08/13 21:40, Benjamin Thaut wrote:
You need to put it into a static if, otherwise the compiler will continue
semantic checks on the second part of the expression. E.g.
template isGraph(G)
{
static if(__traits(hasMember, G, "directed"))
enum bool isGraph = isBoolean!(typeof(G.directed));
else
enum bool isGraph = false;
}
Ahh, right, thanks. :-)
Is there a recommended way for handling the case where there are many such
members -- say about 10 or more? The static if's could become very highly
nested with this approach. I suppose I could go through like this:
static if(!__traits(hasMember, G, "one"))
enum bool isGraph = false;
else static if(!__traits(hasMember, G, "two"))
enum bool isGraph = false;
else static if ...
...
else
{
// Now I know all the members exist and I can
// start checking out their properties ...
}
Aug 30 2013
On 08/30/2013 01:57 PM, Joseph Rushton Wakeling wrote:On 30/08/13 21:40, Benjamin Thaut wrote:How about allSatisfy: AliYou need to put it into a static if, otherwise the compiler will continue semantic checks on the second part of the expression. E.g. template isGraph(G) { static if(__traits(hasMember, G, "directed")) enum bool isGraph = isBoolean!(typeof(G.directed)); else enum bool isGraph = false; }Ahh, right, thanks. :-) Is there a recommended way for handling the case where there are many such members -- say about 10 or more? The static if's could become very highly nested with this approach. I suppose I could go through like this: static if(!__traits(hasMember, G, "one")) enum bool isGraph = false; else static if(!__traits(hasMember, G, "two")) enum bool isGraph = false; else static if ... ... else { // Now I know all the members exist and I can // start checking out their properties ... }
Aug 30 2013
On 30/08/13 23:06, Ali Çehreli wrote:How about allSatisfy:I'll have a look at that, thanks :-) Here's what I came up with, for now. It should probably be extended with further tests on the characteristics of the various member functions but it seems to be sufficient for now: //////////////////////////////////////////////////////// template isGraph(G) { static if (!__traits(hasMember, G, "directed") || !__traits(hasMember, G, "edge") || !__traits(hasMember, G, "edgeCount") || !__traits(hasMember, G, "vertexCount") || !__traits(hasMember, G, "isEdge") || !__traits(hasMember, G, "edgeID") || !__traits(hasMember, G, "addEdge") || !__traits(hasMember, G, "degreeIn") || !__traits(hasMember, G, "degreeOut") || !__traits(hasMember, G, "incidentEdgesIn") || !__traits(hasMember, G, "incidentEdgesOut") || !__traits(hasMember, G, "neighboursIn") || !__traits(hasMember, G, "neighboursOut")) { enum bool isGraph = false; } else static if (!isBoolean!(typeof(G.directed))) { enum bool isGraph = false; } else static if (G.directed && (__traits(hasMember, G, "degree") || __traits(hasMember, G, "incidentEdges") || __traits(hasMember, G, "neighbours"))) { enum bool isGraph = false; } else static if (!G.directed && (!__traits(hasMember, G, "degree") || !__traits(hasMember, G, "incidentEdges") || !__traits(hasMember, G, "neighbours"))) { enum bool isGraph = false; } else { enum bool isGraph = true; } } ////////////////////////////////////////////////////////
Aug 30 2013
Joseph Rushton Wakeling:
static if (!__traits(hasMember, G, "directed") ||
!__traits(hasMember, G, "edge") ||
!__traits(hasMember, G, "edgeCount") ||
!__traits(hasMember, G, "vertexCount") ||
!__traits(hasMember, G, "isEdge") ||
!__traits(hasMember, G, "edgeID") ||
!__traits(hasMember, G, "addEdge") ||
!__traits(hasMember, G, "degreeIn") ||
!__traits(hasMember, G, "degreeOut") ||
!__traits(hasMember, G, "incidentEdgesIn") ||
!__traits(hasMember, G, "incidentEdgesOut") ||
!__traits(hasMember, G, "neighboursIn") ||
!__traits(hasMember, G, "neighboursOut"))
Perhaps can shorten that code writing a hasMembers helper (and I
suggest to keep those names sorted):
static if (hasMembers!(G, "addEdge
degreeIn
...
vertexCount".split) {
Bye,
bearophile
Aug 30 2013
On Fri, Aug 30, 2013 at 11:51:37PM +0200, bearophile wrote:Joseph Rushton Wakeling:[...] Here's a first stab at a possible implementation: /* Warning: untested code */ import std.typetuple : allSatisfy; template isString(T) { // There may already be something in Phobos that does // this, but I'm too lazy to look. enum isString = is(T == string); } template hasMembers(alias T, Members...) if (allSatisfy!isString(Members)) { // Template recursion + exprTuple slicing FTW :) enum hasMembers = __traits(hasMember, T, Members[0]) && hasMembers!(T, Members[1..$]); } void myFunc(G)(G graph) { static if (hasMembers!(G, "directed", "edge", /* ... */)) { ... } } T -- Computers shouldn't beep through the keyhole.static if (!__traits(hasMember, G, "directed") || !__traits(hasMember, G, "edge") || !__traits(hasMember, G, "edgeCount") || !__traits(hasMember, G, "vertexCount") || !__traits(hasMember, G, "isEdge") || !__traits(hasMember, G, "edgeID") || !__traits(hasMember, G, "addEdge") || !__traits(hasMember, G, "degreeIn") || !__traits(hasMember, G, "degreeOut") || !__traits(hasMember, G, "incidentEdgesIn") || !__traits(hasMember, G, "incidentEdgesOut") || !__traits(hasMember, G, "neighboursIn") || !__traits(hasMember, G, "neighboursOut"))Perhaps can shorten that code writing a hasMembers helper (and I suggest to keep those names sorted):
Aug 30 2013
On 30/08/13 23:51, bearophile wrote:Perhaps can shorten that code writing a hasMembers helper (and I suggest to keep those names sorted)Nice thought, I might look into that at some point. :-)
Aug 30 2013









"H. S. Teoh" <hsteoh quickfur.ath.cx> 