Check if a type is an instantiation of a template
I have structs like
struct RGBA (T) {/* ... */}
struct BM开发者_JAVA技巧PFile (DataT) if (is(DataT == RGBA)) {/* ... */}
But is(DataT == RGBA)
cannot work because DataT is a type and RGBA is a template. Instead I need check if a type is an instantiation of a template in order to declare file
like
BMPFile!(RGBA!ushort) file;
In a comment @FeepingCreature showed
struct RGBA(T) {
alias void isRGBAStruct;
}
struct BMPFile (DataT) if (is(DataT.isRGBAStruct)) {}
Although to be working I have no tips on alias void isRGBAStruct
, that seems a hack. Hopefully std.traits will cover this.
I think you're trying to be over-specific. The way I would handle this is to allow any type for DataT
, so long as it implements whatever interface I need.
The way this is done in the D2 standard library, I believe, is to have templates like IsIntegral
that test various properties of a type.
For example, let's say your requirement for DataT
is that you can finangle
it. You might write:
template IsAppropriate(DataT)
{
enum IsAppropriate = is(typeof( { DataT d; d.finangle(); }() ));
}
Take the above with a grain of salt: I haven't tested it, but I believe that's the basic pattern. If you aren't familiar with the above, what it's doing is checking to see if the given anonymous function compiles; it can only compile if it's possible to finangle
the DataT
.
This is all from memory so take it with a bit of salt.
First, those structs need bodies, you should be getting parse errors from that. Second, the template constraint on BMPFile
won't work because it is attempting to compare RGBA!ushort
(a type) and RGBA
(a template) which are different kinds of things. Last I checked (and it's been a while) there is no clean way to check if a type is an instantiation of a given template.
Once a template is instantiated, it's its own beast. If you have struct such as
struct RGBA(T)
{
}
you can't directly test whether a particular instantiation of that struct is an instantation of that struct. You can test something like is(RGBA!int == RGBA!int)
or is(RGBA!T == RGBA!int)` (if you have a T), but there is no way to ask whether a generic type is an instantiation of RGBA.
The reason for this is essentially because RGBA is not a type. It's a template for a type. No type exists until you instantiate the template, and no instantiation of a template has any relation to any other instantation of a template. RGBA!int has no relation to RGBA!float. Thanks to template constraints and template specializations and the like, the two types could be completely different. e.g.
struct RGBA(T : int)
{
float a;
double b;
bool[] c;
}
struct RGBA(T : float)
{
@property int w() const pure nothrow
{
return 2;
}
}
Now, there are games that you can play if you're willing to restrict yourself slightly. The trick is that you need a way to get the T that would be used to instantiate RGBA. So, something like this would work:
import std.traits;
struct RGBA(T)
{
}
struct BMPFile(DataT, T)
if(is(DataT == RGBA!T) &&
IsIntegral!T)
{
}
Now, this has the restriction that T is an integral type, which may or may not be what you want. isFloatingPoint!()
would work, as would is(T == bool)
, and a number of functions in std.traits
and traits in __traits
. So, if you have some idea of what T will be, you can add appropriate constraints to check the type of T.
Now, if you did something like
struct BMPFile(DataT, T)
if(is(DataT == RGBA!T))
and then always gave the type a second time, that would work too: BMPFile(RGBA!int, int)
(though I'm guessing that you don't really want to do that).
Another option would be if you know that there's a function on RGBA which returns T
or takes a T
, you could test whether that function is present on DataT, and use traits to get at the type. e.g.
import std.traits;
struct RGBA(T)
{
T func() { return T.init;}
}
struct BMPFile(DataT, T = ReturnType!(DataT.func))
if(is(DataT == RGBA!T))
{
}
However, the error messages for that can get pretty ugly when you pass it something which doesn't have a func
function, and if a type other than one instantiated from RGBA manages to match the template, it'll try and instantiate it, which may or may not work but probably isn't what you want in either case.
So, what it comes down to is that there is not currently any way to do what you're trying to do directly, but if you play some games, you can get something which will work. Essentially, it comes down to finding a way to define the template such that you have access to the arguments which were used to instantiate the first template (RGBA
in this case) so that you can test whether the type (DataT
) given to the second template (BMPFile
) is an instantiation of that type (RGBA!T
). If you can get ahold of T
, then you can test whether is(DataT == RGBA!T)
.
精彩评论