Well, there is a way but it might wreak havoc on your object size since it will instantiate a lot of templates. Therefore it would be a good thing to only do it in debug mode:
import std.string; class A { int opIndexDebug(int line = __LINE__, string file = __FILE__)(int x) { /* do a bunch of checks */ throw new Exception(format("%s: %s", file, line)); int value; /* compute value */ return value; } debug alias opIndexDebug opIndex; else alias opIndexDebug!(__LINE__, __FILE__) opIndex; } void main() { auto a = new A; auto b = a[1]; } You see, when using debug mode it gets instantiated on every call site, whereas in release mode it uses one hardcoded template instance. Of course you might want the file/line in release mode too, in that case get rid of the aliases and just use the templated opIndex (but then again DMD doesn't merge templates so this could be a hit on performance).