On Monday, 12 February 2024 at 17:00:01 UTC, Atila Neves wrote:
>On Wednesday, 7 February 2024 at 21:26:51 UTC, jmh530 wrote:
>On Wednesday, 7 February 2024 at 10:10:27 UTC, Atila Neves wrote:
>[snip]
The problem with this approach, as C++ found out, is that Vector!(int, MyAlloc)
is a different type from Vector!(int, YourAlloc)
. The way I got around that is by defaulting to a global allocator. This has its drawbacks as well of course, because now everything is a virtual call.
If you need to allocate or deallocate, then it's useful to treat them as separate types. Otherwise it's not.
alias MyVec = Vector(MyType, Mallocator);
void fun(MyVec vec) {
// just before the curly brace, the elements and storage for them get deallocated.
}
I assume you mean alias MyVec = Vector!(MyType, Mallocator);
.
I'm not completely sure I'm getting to the heart of what you're saying since your post is a bit sparse...but I'm doing my best.
Your fun
function only works for MyVec
, which depends on MyType
and Mallocator
. It isn't general across either types or allocators. It's kind of the essence of your complaint about C++ and treating Vector!(int, MyAlloc)
and Vector!(int, YourAlloc)
as different types, except you are pushing all the work downstream to functions. In other words, you have to have separate fun
for all the different types and allocators you pass, and then have different allocation strategies for each. Multiply that across all the other functions.
If all the allocators are consistent with the interface from std.experimental.allocator
, then you might be able to make the allocation more general. But, it becomes frustrating to rely on template aliases. The compiler can't see through them due to issue 1807 [1]. The more general approach is to use template constraints (see example below). The problem with the template constraint approach is that it leads to template bloat, which is why I suggested the alias this
approach above.
Another approach would be to pass the allocator to the function instead of making it part of the type. The problem with this is that for some allocators you need to know what did the allocating in order to free it safely.
import std.stdio;
struct Vector(T, U) { T x; U y;}
alias MyVec = Vector!(double, int);
void fun(MyVec vec)
{
writeln("works");
}
alias MyVec2(T) = Vector!(T, int);
void fun2(T)(MyVec2!T vec)
{
writeln("works2");
}
void fun3(T)(T vec)
if (is(T : Vector!(U, int), U))
{
writeln("works3");
}
void main() {
MyVec vec = MyVec(1.0, 1);
fun(vec); // prints works
//fun2(vec); //error
fun2!double(vec); // prints works2
fun3(vec); // prints works3
}