passing duck-typed objects and retaining full type information
Adam Taylor via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Tue Nov 11 11:23:38 PST 2014
* i apologize in advance, this is my first post -- the code
formatting probably wont turn out so great...
I have a bunch of duck typed interfaces for "containers" similar
to what you would find in std.range.
i.e.
template isContainer(C)
{
enum bool isContainer = is(typeof(
(inout int = 0)
{
C c = C.init;
...
}));
}
template canRemoveFromContainer(C)
{
enum bool canRemoveFromContainer = isContainer!C && is(typeof(
(inout int = 0)
{
C c = C.init;
c.remove();
}));
}
Now what i want to do is pass some such "container" object to an
interface function:
interface MyInterface
{
void filterCollisions(S)(S collisionCandidates)
if(canRemoveFromContainer!S)
}
but of coarse templates and interfaces don't get along so well.
so...so far as I know i would need to do something like this:
interface MyInterface
{
final void filterCollisions(S)(S collisionCandidates)
if(canRemoveFromContainer!S)
{
filterCollisionsImpl(...);
}
void filterCollisionsImpl(...)
}
and pass something to filterCollisionsImpl that is a "proper"
class or interface type.
So here's the problem: many of the "duck-typed" interfaces
cannot be converted to proper interfaces without losing
something. So is there ANY way to pass in
a very basic class or interface Container type and call the
remove function on it? Here's what i've tried:
interface Container(C)
{
...
}
template ContainerObject(C) if (isContainer!(Unqual!C)) {
static if (is(C : Container!(ElementType!C))) {
alias ContainerObject = C;
} else static if (!is(Unqual!C == C)) {
alias ContainerObject = ContainerObject!(Unqual!C);
} else {
static if (__traits(compiles, { enum e = C.ValueType; })) {
alias ValueType = C.ValueType;
} else {
alias ValueType = ElementType!C;
}
class ContainerObject : Container!ValueType {
C _container;
this(C container) {
this._container = container;
}
static if(canRemoveFromContainer!C) {
size_t remove()
{
return _container.remove();
}
}
}
}
}
ContainerObject!C containerObject(C)(C container) if
(isContainer!C) {
static if (is(C : Container!(ElementType!C))) {
return container;
} else {
return new ContainerObject!C(container);
}
}
interface MyInterface
{
final void filterCollisions(S)(S collisionCandidates)
if(canRemoveFromContainer!S)
{
auto container = containerObject(collisionCandidates);
container.remove(); // works just fine -- have the complete
type info at instantiation site
filterCollisionsImpl();
}
void filterCollisionsImpl(Container!string collisionCandidates)
collisionCandidates.remove(); // error -- some type info is lost
here, only have a Container!string which doesn't have a remove
function.
}
More information about the Digitalmars-d-learn
mailing list