Concepts vs template constraints - the practical approach
Ali Çehreli
acehreli at yahoo.com
Sun Nov 20 10:47:39 PST 2011
On 11/20/2011 08:41 AM, Norbert Nemec wrote:
> Hi there,
>
> back in the discussions about C++-"concepts" it was argued that
> D-template-parameter constraints allow you to achieve the same goal.
Have a look at std.range.hasLength, std.range.isInputRange, and friends.
> Now, I find it fairly difficult to come up with a clean solution for
> this that actually scales up for complex libraries. My best attempt so
> far is as follows:
>
> ===================================================
>
> template verifyMyConcept(A) {
> static assert(is(A.type));
> static assert(A.len >= 0);
> static assert(is(typeof(A.init[0]) == A.type));
> }
>
> struct MyClass(T,int R) {
> alias T type;
> enum len = R;
>
> T[R] value;
>
> T opIndex(int idx) {
> return value[idx];
> }
>
> mixin verifyMyConcept!(typeof(this));
> }
>
> void myfunction(A)(A arr)
> if(__traits(compiles, verifyMyConcept!(A)))
> {
> }
>
> unittest {
> MyClass!(int,4) x;
>
> mixin verifyMyConcept!(typeof(x));
> myfunction(x);
> }
>
> ===================================================
>
> As you can see, this approach attempts to define all the requirements
> for MyConcept in one place as individual static assertions. This permits
> error messages to identify which requirement for the concept is not met.
>
> Still the code seems fairly ugly to me and the error message is not
> quite clear enough for my taste.
>
> Ideally, there should be a way to use "concepts" similar to interfaces:
>
> a) A concept should be defined readably in one place, listing a set of
> requirements, possibly inheriting other concepts.
I have separated the parts of the concepts below and then defined
matchesMyConcept to "inherit" them.
> b) A struct implementing the concept should state this in a similar way
> to a class that implements an interface.
>
> c) A template that requires a parameter to fulfil a concept should state
> this in a similar way to a function requiring a specific input type
>
> and most importantly:
>
> d) a user of the library should get a clear and simple error message
> when using templates with parameters that do not fulfil the required
> concept.
Although the following code works acceptably with dmd 2.056, sometimes
the error messages are less than ideal. This may happen when there are
overloads of a function template and none of them accept a template
parameter. The compiler can only say that "there is no function template
for this use".
>
> Has anyone achieved these goals better than my feeble attempt?
>
> Greetings,
> Norbert
Here is something:
template hasType(T)
{
enum bool hasType = is(T.type);
}
template hasNonNegativeLength(T)
{
enum bool hasNonNegativeLength = T.len >= 0;
}
template firstElementSameType(T)
{
enum bool firstElementSameType = is(typeof(T.init[0]) == T.type);
}
template matchesMyConcept(T)
{
enum bool matchesMyConcept = (hasType!T &&
hasNonNegativeLength!T &&
firstElementSameType!T);
}
struct MyClass(T,int R) {
alias T type;
enum len = R;
T[R] value;
T opIndex(int idx) {
return value[idx];
}
}
struct YourClass
{}
void myfunction(A)(A arr)
if (matchesMyConcept!A)
{
}
unittest {
MyClass!(int,4) x;
myfunction(x); // <-- this works fine
YourClass y;
myfunction(y); // <-- compilation ERROR for this one
}
void main()
{}
Ali
More information about the Digitalmars-d
mailing list