How can I have those "template instance recursive expansion" errors under control?

realhet real_het at hotmail.com
Sat Nov 30 18:11:56 UTC 2024


I have a big example code (compared to me) for this particular 
case, I can't include example as narrowing it down would take 
several hours.

I just ask you to give me general tips to avoid it.

How can I detect them earlier for example?
Is it a way analyze the --vtemplates compiler output and detect 
weak spots?

I already know a few effective workarounds (I learned from the 
other template recursion topics here):
- Don't use dynamic returns. Put all the cases into static if 
else chains.
- If the "template instance recursive expansion" pops up, narrow 
the import clause to individual names.

I have a vector/matrix/2d-image math module.  Most of the times 
the error pops there because there is a lot of template work 
there.  But I know it can pop anywhere, this time it is inside my 
traits.isNumeric() inside my vector.opBinary().  Is there a way 
to access the full instation path?  Maybe it could show me a bug.

I just put there some sources near the error message, maybe 
someone can spot a terrible mistake.
Thank you in advance!

(LDC 1.40 Win64)
```d
private template OperationResultType(string op, A, B)
{
	static if(op.among("<<", ">>", ">>>"))	alias OperationResultType 
= A;
	else	alias OperationResultType = CommonType!(A, B);
}

auto generateVector(CT, alias fun, T...)(in T args)
{
	static if(anyVector!T)
	{
		Vector!(CT, CommonVectorLength!T) res;
		static foreach(i; 0..res.length)
		res[i] = cast(CT) mixin("fun(", T.length.iota.map!(j => 
"args["~j.text~"].vectorAccess!i").join(','), ")");
		return res;
	}
	else
	{ return cast(CT) fun(args); }
}

struct Vector(CT, int N)
if(N.inRange(2, 4))
{

    ... lots of code ...

    private static binaryVectorOp(string op, A, B)(in A a, in B b)
    {
	alias CT = OperationResultType!(op, ScalarType!A, ScalarType!B);
	return generateVector!(CT, (a, b) => mixin("a", op, "b") )(a, b);
    }

    auto opBinary(string op, T)(in T other) const
    {
	static if(isNumeric!T || isVector!T)
                 //^^^^^^^^^^^  Here the compiler decided that 
enough is enough :S
                 //Error: template instance /+Code: 
std.traits.isNumeric!(Vector!(float, 3))+/ recursive expansion
	{
		//vector * (scalar or vector)
		return binaryVectorOp!op(this, other);
	}
	else static if(op=="*" && isMatrix!T && T.height==length)
	{
		//vector * matrix
		return other.transpose * this;
		//Opt: this is slow if it is not unrolled.
	}
	else static if(op=="in" && isBounds!T && T.VectorLength == 
length)
	{ return other.contains(this); }
	else static if(op=="in" && isImage!T && T.Dimension == length)
	{ return other.contains(this); }
	else static if(op.among("+", "*") && isBounds!T && 
T.VectorLength == length)
	{ return other.opBinary!op(this); }
	else
	{ static assert(false, "Unhandled operation: "~op~" 
"~T.stringof); }
    }

    ... lots of code ...
}
```


More information about the Digitalmars-d-learn mailing list