Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 23, 2014 Check for presence of function | ||||
---|---|---|---|---|
| ||||
What's the cool/idiomatic D way to test at compile time if a struct has a member function with a particular signature? Along the lines of: struct Unrelated { ... } template isSomething(T) { enum bool isSomething = is(typeof( (inout int = 0) { T???; // has a function void doSomething(Unrelated* up); // etc })); } struct Thingie { ... } static assert(isSomething!(Thingie)); Thanks Steve |
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steve Teale | template isSomething(T) { enum isSomething = is(typeof(__traits(getMember, T, "doSomething")) == function) && is(typeof(&__traits(getMember, T, "doSomething")) : void function(Unrelated*)); } |
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steve Teale | On Sun, Mar 23, 2014 at 1:40 PM, Steve Teale <steve.teale@britseyeview.com> wrote:
> What's the cool/idiomatic D way to test at compile time if a struct has a member function with a particular signature? Along the lines of:
>
> struct Unrelated
> {
> ...
> }
>
> template isSomething(T)
> {
> enum bool isSomething = is(typeof(
> (inout int = 0)
> {
> T???; // has a function void doSomething(Unrelated* up);
> // etc
> }));
> }
>
> struct Thingie
> {
> ...
> }
>
> static assert(isSomething!(Thingie));
You can use __traits(compiles, /* some code */), like this:
struct Unrelated {}
template isSomething(T)
{
enum bool isSomething = __traits(compiles,
{
Unrelated* up;
T.init.doSomething(up);
}
);
}
struct Thingie
{
void doSomething(Unrelated* up) {}
}
void main()
{
pragma(msg, isSomething!Thingie); // true
pragma(msg, isSomething!Unrelated); // false
pragma(msg, isSomething!int); // false
}
|
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Ideally, the alias part of the grammar could be extended and isSomething simplified as: alias isSomething(T) = __traits(compiles, { Unrelated* up; T.init.doSomething(up); } ); But this is not accepted by the grammar right now, because of __traits() |
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Philippe Sigaud | On Sunday, 23 March 2014 at 12:57:36 UTC, Philippe Sigaud wrote:
> But this is not accepted by the grammar right now, because of __traits()
That's easy enough to work around with an alias helper:
alias helper(alias T) = T;
alias isSomething(T) = alias!(__traits(compiles,
{
Unrelated* up;
T.init.doSomething(up);
}
));
|
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Sunday, 23 March 2014 at 13:00:09 UTC, Adam D. Ruppe wrote:
> alias isSomething(T) = alias!(__traits(compiles,
oops that should say helper! not alias!
|
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Sunday, 23 March 2014 at 12:53:39 UTC, Dicebot wrote:
> template isSomething(T)
> {
> enum isSomething =
> is(typeof(__traits(getMember, T, "doSomething")) == function)
> && is(typeof(&__traits(getMember, T, "doSomething")) : void function(Unrelated*));
> }
That won't necessarily work in the presence of overloaded functions since getMember only gets one of them.
You could though do this:
template isSomething(T) {
bool checker() {
foreach(overload; __traits(getOverloads, T, "doSomething"))
static if(is(typeof(overload) == void function(Unrelated*)))
return true;
return false;
}
enum isSomething = checker();
}
getOverloads returns an empty tuple for non-functions so you don't even have to check that ahead of time.
|
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Sunday, 23 March 2014 at 13:03:07 UTC, Adam D. Ruppe wrote:
> That won't necessarily work in the presence of overloaded functions since getMember only gets one of them.
Yeah, forgot to add this part, will make end result a bit less pretty indeed.
Updated version with overloads will be more reliable than proposed duck-typing version as it won't false trigger in presence of "alias this" or opDispatch. Though Steve may actually want it to trigger, I don't know.
|
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
On 3/23/14, Philippe Sigaud <philippe.sigaud@gmail.com> wrote:
> But this is not accepted by the grammar right now, because of __traits()
Pretty sure it's because you're using 'alias' instead of 'enum'. This works:
-----
enum isSomething(T) = __traits(compiles,
{
int up;
T.init.doSomething(up);
}
);
void main()
{
static struct S { void doSomething(int); }
static struct X { void doSomething(string); }
static assert(isSomething!S);
static assert(!isSomething!X);
}
-----
|
March 23, 2014 Re: Check for presence of function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Sunday, 23 March 2014 at 13:23:58 UTC, Dicebot wrote:
> On Sunday, 23 March 2014 at 13:03:07 UTC, Adam D. Ruppe wrote:
>> That won't necessarily work in the presence of overloaded functions since getMember only gets one of them.
>
> Yeah, forgot to add this part, will make end result a bit less pretty indeed.
>
> Updated version with overloads will be more reliable than proposed duck-typing version as it won't false trigger in presence of "alias this" or opDispatch. Though Steve may actually want it to trigger, I don't know.
DB,
In my particular question, I would not have wanted, or cared if alias this was triggered, but that was a narrow view.
My primary point is that there should be something in the wiki to help old-fashioned programmers like me to change from an OOP style that is not 100% necessary, to a struct based style that should be quicker, but that allows the compiler to help me, or other contributors to the same project, to write add-on components that are at least checked at compile time.
So what I'm after really, is how do you do interfaces outside of OOP.
Std.range does that sort of thing in what seem to me to be very simple cases, but there is a lot of scope for different scenarios.
Thanks for your answer
Steve
|
Copyright © 1999-2021 by the D Language Foundation