I want to define a general-purpose centroid computer for point containers and ran into a couple of challenges. Firstly, here is the basic code
Point3 computeCentroid(PointContainer)(const ref PointContainer C) if (...) // want a signature constraint for usability of foreach { Point3 c = Point3(0.0, 0.0, 0.0); size_t total = 0; foreach(Point3 p; C) { // enforce that the container supports this c += p; ++total; } if (total > 0) c /= cast(double)(total); return c; } I want to have the most generally-applicable version of this functionality (for const/immutable/etc containers supporting foreach in various ways), ideally without needing to write multiple versions of this function. 1. Since support for foreach can be added in many ways (with ref/non-ref/const variants), I wanted to check if there was any signature constraint that could check if the container supports foreach as above. I looked into the "compiles" traits, but that doesn't work for statements. For an opAssign version, I had tried if (is(typeof(C.opApply(delegate(const ref Point3) { return 1;})))) but this is unelegant because the container's opApply could have instead supplied delegate(Point3) or delegate(ref Point3) (although the latter would require me to not use a "const" on the parameter declaration). 2. Secondly, TDPL on page 381 says that foreach iterates over C[], if C defines the opSlice() function without any arguments. However the code above doesn't seem to work and requires me to explicitly invoke the slice operator myself like foreach(p; C[]) { ... } when my data structure clearly defines the following functions. Point3[] opSlice() { return _cpts[]; } const (Point3)[] opSlice() const { return _cpts[]; } Is this a misunderstanding on my part or an unimplemented feature? 3. A more general question: Is there any by any chance a way to avoid the redundancy above of defining two opSlice() functions (or two opAssign() functions if I went that route -- one for const and another for ref)? I suspect that the answer is no, but I just wanted to verify.