Reputation: 300079
If I have a small struct Test
:
struct Test<T> { a: T }
And I wish, in a method of Test
to refer to its full type:
impl<T> Test<T> {
fn new(a: T) -> Test<T> {
type X = Test::<T>;
println!("{}", std::intrinsics::type_id::<X>());
Test { a: a }
}
}
This fails with expected ident, found <
, and the following fail too:
type X = Test;
: wrong number of type arguments: expected 1, found 0 [E0243]
type X = Test<T>;
: can't use type parameters from outer function; try using a local type parameter instead with a note use of undeclared type name T
Actually, it makes sense that the former two are rejected; the latter however is slightly more mysterious.
This came about in trying to implement an offset_of!
macro: offset_of($T:ty, $field:ident)
; the macro works rather well, however ty
does not accept Test<T>
(but accept a parameter-less alias).
Is there any way to either:
self
, even in generics?Test<T>
as a "type" argument?Note: I would prefer a solution to the former, if possible, as aliases are really handy.
For reference, here is the offset_of
macro I crafted:
macro_rules! offset_of(
($T:ty, $field:ident) => {
unsafe {
let exemplar: $T = std::mem::uninitialized();
let base: *const u8 = std::mem::transmute(&exemplar);
let attr: *const u8 = std::mem::transmute(&exemplar.$field);
std::mem::forget(exemplar);
(attr as isize) - (base as isize)
}
}
);
Upvotes: 2
Views: 1301
Reputation: 431589
I may be misunderstanding you, but there already is an alias for the type of self — Self
:
#![feature(core)]
struct Test<T> { a: T }
impl<T> Test<T> {
fn new(a: T) -> Test<T>
where T: 'static
{
println!("{}", unsafe { std::intrinsics::type_id::<Self>() });
Test { a: a }
}
}
fn main() {}
I had to add the feature gates, make T
'static
to satisfy type_id
, and add an unsafe block. I hope that none of that seems suspicious. This seems to work with your alias, as well:
macro_rules! offset_of(
($T:ty, $field:ident) => {
unsafe {
let exemplar: $T = std::mem::uninitialized();
let base: *const u8 = std::mem::transmute(&exemplar);
let attr: *const u8 = std::mem::transmute(&exemplar.$field);
(attr as isize) - (base as isize)
}
}
);
struct Test<T> { a: T, b: T, c: T }
impl<T> Test<T> {
fn new(a: T) -> Test<T>
where T: Copy
{
println!("{}", offset_of!(Self, a));
println!("{}", offset_of!(Self, b));
println!("{}", offset_of!(Self, c));
Test { a: a, b: a, c: a }
}
}
fn main() {
Test::new(1u16);
}
Upvotes: 3