Related thread: https://forum.dlang.org/thread/wgvtwckvjyhnbpcuyyqy@forum.dlang.org
It seems dtemplate.deduceType
does all the deduction for both is
and IFTI. I can already add a better error message, right before "goto Lnomatch":
cannot deduce the instantiation of an alias template
(is that the right term?)
This will better explain to new users why it really fails:
NOT because no callable candidate exists, but because D never tried to do anything about an alias template to find the match. So try instantiating the function explicitly then it will work.
But my goal is:
struct Matrix(U, size_t M, size_t N)
{
U[M * N] data;
}
alias Vector3(U) = Matrix!(U, 3, 1);
alias Vec3(U) = Vector3!U;
alias Vec3Alt = Vector3;
alias Vec3Var(U...) = Vector3!(U);
alias V3(U) = Vector3!U;
alias Identity(U) = int;
void foo1(U)(in Vector3!U a)
{
}
void foo2(U)(in Vec3!U v)
{
}
void foo2Alt(U)(in Vec3Alt!U v)
{
}
void foo3Var(U...)(Vec3Var!(U))
{
}
void foo3(U)(in V3!U)
{
}
void foo4(U)(Identity!U u)
{
}
void main()
{
auto instVar = Vector3!float();
// The current behaviour is: deduction for alias template will always fail.
// foo1(instVar); // expect OK
// foo2(instVar); // expect OK
// foo2Alt(instVar); // expect OK
// foo3Var(instVar); // expect OK
// foo3(instVar); // expect OK
// foo4(Identity!int()); // let it fail
// import std.regex;
// import std.traits;
// static assert(isInstanceOf!(Regex, Regex!char)); // now fails, not sure it can be fixed along
}
How I like it to behave is based on what C++ offers.
template <typename T, size_t M, size_t N>
struct Matrix {
T data[M * N];
};
template<typename T, size_t M, size_t N>
using Mat = Matrix<T, M, N>;
template <typename T>
using Vector3 = Matrix<T, 3, 1>;
template <typename T>
using Vec3 = Vector3<T>;
template <typename T>
using Identity = int;
template <typename T>
void foo1(const Vector3<T>& v) {
}
template <typename T>
void foo2(const Vec3<T>& v) {
}
template <typename T, size_t M, size_t N>
void foo3(const Mat<T, M, N>& v) {
}
template <typename T>
void foo4(const Identity<T> id) {
}
int main() {
foo1(Vector3<float>()); // OK
foo2(Vector3<float>()); // OK
foo3(Vector3<float>()); // OK
// Let it fail
// foo4(Identity<int>()); // no matching overloaded function found.
}
My current idea is to "expand" the alias with its to-be-matched parameter(s) to the fullest form if possible (for example, V3!U > Vec3!U > Matrix!(U, 3, 1)), then go to the parameter matching routine.
It seems possible, if I just follow TemplateDeclaration.onemember
and expand the expression level by level, give up when running into overloads, conditions, or anything too complicate (I'm not sure if onemember
ensures no conditions). I could be wrong, but based on my few hours of reading the code and really helpful comments in the forum, I believe people who are more familiar with the compiler code can implement it instantantly.
I'm making this post not to promise to fix it (I'll try), but to gather opinions:
Do you think such behaviour in D is desirable (regardless of how I imagine it can be implemented)?
What do I miss?