Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 02, 2006 Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
I have a question and a suggestion: Is it possible to determine whether a given class contains a specific member function? It would be useful to be able to create a template for classes that have certain functions without requiring the user to inherit from an interface. One idea I've heard is to use "concepts" (a possible extension to C++) where code would go as follows concept Collection(T) { bool add(T t); bool isEmpty(); .. } template doSomething(CollectionType : Collection) { void doSomething(CollectionType t) { ... } } This would allow the compiler to give a clearer error message to people who try to use the template with a class that doesn't fit the Collection concept. Instead of errors about undefined functions the user would be told something like "Error: T does not fit the Collection concept [and maybe list the missing functions'". |
March 02, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Phillips | In article <du751p$1imp$1@digitaldaemon.com>, Ben Phillips says... > >I have a question and a suggestion: >Is it possible to determine whether a given class contains a specific member >function? > >It would be useful to be able to create a template for classes that have certain >functions without >requiring the user to inherit from an interface. One idea I've heard is to use >"concepts" (a possible >extension to C++) where code would go as follows > >concept Collection(T) >{ >bool add(T t); >bool isEmpty(); >.. >} > >template doSomething(CollectionType : Collection) >{ >void doSomething(CollectionType t) { ... } >} > >This would allow the compiler to give a clearer error message to people who try >to use the template >with a class that doesn't fit the Collection concept. Instead of errors about >undefined functions the user >would be told something like "Error: T does not fit the Collection concept [and >maybe list the missing >functions'". > > I should probably have clarified that a class would not have to inherit from a concept to qualify for a template. It would only have to have functions (and possibly aliases) of the same names. Concepts would also only be used to help specialize templates. It would be illegal to do something like concept Queue { ... } void foo() { Queue q = new QueueClassThatFitsConcept(); // error, concepts aren't types and can't be instantiated. Use interfaces in this case } Also, most importantly, since concepts aren't types and classes that "fit" a concept don't inherit from them there is no virtual function overhead (actually a class doesn't even have to know the concepts it fits). |
March 02, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Phillips | In article <du751p$1imp$1@digitaldaemon.com>, Ben Phillips says... > >Is it possible to determine whether a given class contains a specific member function? > From reading the docs it seems like I should be able to do this using "is", but the appropriate syntax is unclear and I can't seem to figure it out. Does "is" make it possible to test of a class has a certain member function and, if so, what is the correct syntax? |
March 02, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Phillips | "Ben Phillips" <Ben_member@pathlink.com> wrote in message news:du751p$1imp$1@digitaldaemon.com... > One idea I've heard is to use > "concepts" (a possible > extension to C++) where code would go as follows Concepts are an interesting idea. As far as I know, nobody has implemented it for C++ so nobody knows if it really works or not. |
March 02, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> "Ben Phillips" <Ben_member@pathlink.com> wrote in message news:du751p$1imp$1@digitaldaemon.com...
>> One idea I've heard is to use
>> "concepts" (a possible
>> extension to C++) where code would go as follows
>
> Concepts are an interesting idea. As far as I know, nobody has implemented it for C++ so nobody knows if it really works or not.
Now that static if is ignored for template expansion, concepts aren't as necessary as they once were. For example, this is how I'd have implemented concepts in D before, which is fairly close to how it would be done in C++:
struct DoesNiftyThingA {}
struct DoesNiftyThingB {}
struct DoesntDoAnything {}
template testFeatures( T )
{
static if( /* test for A */ )
alias DoesNiftyThingA testFeatures;
else static if( /* test for B */ )
alias DoesNiftyThingB testFeatures;
else
alias DoesntDoAnything testFeatures;
}
// specialization for A
template conceptFn( T, T1 : DoesNiftyThingA = testFeatures!(T) )
{
static assert( is(testFeatures!(T) == DoesNiftyThingA );
void conceptFn() {}
}
// specialization for B
template conceptFn( T, T1 : DoesNiftyThingB = testFeatures!(T) )
{
static assert( is(testFeatures!(T) == DoesNiftyThingB );
void conceptFn() {}
}
// default implementation
template conceptFn( T )
{
static assert( is(testFeatures!(T) == DoesNiftyThingB );
void conceptFn() {}
}
But using the template parameter list is unwieldy and error-prone (this the static asserts). However, the equivalent now could be:
template conceptFn( T )
{
static if( /* test for A */ )
void conceptFn() {}
else static if( /* test for B */ )
void conceptFn() {}
else
void conceptFn() {}
}
And pragmas make it fairly easy to provide meaningful error messages if there is no default:
template conceptFn( T )
{
static if( /* test for A */ )
void conceptFn() {}
else static if( /* test for B */ )
void conceptFn() {}
else
{
pragma( msg, "conceptFn is not defined for this type." );
static assert( false );
}
}
Coupled with Don's template string magic, it should be fairly simple to improve the error message to include the supplied type name, etc.
So... while I think concepts may still be nice to have, I'm not sure there's a pressing need for them any longer. In fact, I think I'm going to go back and rewrite my template code to use the "static if" method above, as most of it still uses the old C++ style.
Sean
|
March 02, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote:
>
> // default implementation
> template conceptFn( T )
> {
> static assert( is(testFeatures!(T) == DoesNiftyThingB );
> void conceptFn() {}
> }
paste error, the above should not contain an assert. Also, my C++ style example even used "static if" in the "new" way. A true representation would actually be slightly longer/more complex.
Sean
|
March 02, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Phillips | Ben Phillips wrote:
> In article <du751p$1imp$1@digitaldaemon.com>, Ben Phillips says...
>>
>>Is it possible to determine whether a given class contains a specific member function?
>>
>
> From reading the docs it seems like I should be able to do this using "is", but the appropriate syntax is unclear and I can't seem to figure it out. Does "is" make it possible to test of a class has a certain member function and, if so, what is the correct syntax?
I'm not fully sure of the syntax, but this seems to work:
To test if a class T contains a method test:
is(typeof(T.test) == function)
Or conceptualized:
template Testable(T) {
const Testable = is(typeof(T.test) == function));
}
One could wish that you could write something like:
is(typeof(T.test) == int function(T))
To make sure that the function signature is OK, but this does not seem to work.
Instead, the following works kind of but doesn't check the exact type of the arguments. To check if T contains a method with the signature similar to int test(int,int,int):
is(typeof((new T).test(1,1,1)) == int)
But will be true for e.g. a int test(real,real,real) too...
/Oskar
|
March 03, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | In article <du7qud$2ji7$1@digitaldaemon.com>, Sean Kelly says... >Coupled with Don's template string magic, it should be fairly simple to improve the error message to include the supplied type name, etc. > >So... while I think concepts may still be nice to have, I'm not sure there's a pressing need for them any longer. In fact, I think I'm going to go back and rewrite my template code to use the "static if" method above, as most of it still uses the old C++ style. > > >Sean While this is true, if you have a large interface to check for compatability with, template code can still become messy. |
March 03, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Oskar Linde | In article <du7sda$2kmq$1@digitaldaemon.com>, Oskar Linde says... > >Ben Phillips wrote: > >> In article <du751p$1imp$1@digitaldaemon.com>, Ben Phillips says... >>> >>>Is it possible to determine whether a given class contains a specific member function? >>> >> >> From reading the docs it seems like I should be able to do this using "is", but the appropriate syntax is unclear and I can't seem to figure it out. Does "is" make it possible to test of a class has a certain member function and, if so, what is the correct syntax? > >I'm not fully sure of the syntax, but this seems to work: > >To test if a class T contains a method test: > >is(typeof(T.test) == function) > >Or conceptualized: > >template Testable(T) { > const Testable = is(typeof(T.test) == function)); >} > >One could wish that you could write something like: > >is(typeof(T.test) == int function(T)) > >To make sure that the function signature is OK, but this does not seem to work. > >Instead, the following works kind of but doesn't check the exact type of the arguments. To check if T contains a method with the signature similar to int test(int,int,int): > >is(typeof((new T).test(1,1,1)) == int) > >But will be true for e.g. a int test(real,real,real) too... > >/Oskar Ah.. thanks! This helps a lot. You pointed out that your last method for testing method signature and arguments can be slightly ambiguous, but I doubt this will pose a problem in most real world scenarios. |
March 03, 2006 Re: Concepts? Template specialization depending on class functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Phillips | Ben Phillips wrote:
> In article <du7qud$2ji7$1@digitaldaemon.com>, Sean Kelly says...
>> Coupled with Don's template string magic, it should be fairly simple to improve the error message to include the supplied type name, etc.
>>
>> So... while I think concepts may still be nice to have, I'm not sure there's a pressing need for them any longer. In fact, I think I'm going to go back and rewrite my template code to use the "static if" method above, as most of it still uses the old C++ style.
>
> While this is true, if you have a large interface to check for compatability
> with, template code can still become messy.
Yup. I briefly considered private functions with aliases inside the static if:
private implA() {}
private implB() {}
template conceptFn( T ) {
static if( /* supports A */ )
alias implA conceptFn;
else if( /* supports B */ )
alias implB conceptFn;
else
{ pragma( msg, "Not supported." );
static assert( false );
}
}
But I ultimately decided to simply format and comment things in a way that was as readable as possible.
Sean
|
Copyright © 1999-2021 by the D Language Foundation