开发者

Check if a type is an instantiation of a template

开发者 https://www.devze.com 2023-02-01 11:29 出处:网络
I have structs like struct RGBA (T) {/* ... */} struct BM开发者_JAVA技巧PFile (DataT) if (is(DataT == RGBA)) {/* ... */}

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).

0

精彩评论

暂无评论...
验证码 换一张
取 消