There's a big problem with your approach that has less to do with C++ and more to do with Vulkan. Specifically:
minor version of vulkan can add an unknown number of these structs
This tells me that you intend to apply such technology to VkPhysicalDeviceFeatures2
, as well as any feature struct which can appear in its pNext
chain. Hence the "an unknown number of these structs".
Well, here's the thing: VkPhysicalDeviceFeatures2
is not just a bunch of VkBool
s. It is an extensible Vulkan struct, which means that it starts with the sType
and pNext
fields common to such structures. So are all of the post-1.0 Vulkan device feature structs.
Code that can do what you've stated with post-1.0 feature structs must be able to take an entire pNext
chain of feature structs and test them. And in order to do that, you have to know what they are. There's no way to query, from just a pointer to arbitrary data, that this data contains X number of VkBool
s.
To make this work, you will need to be able to map an sType
value to the size of that structure. And therefore, it cannot be automatically extensible (and no, C++ reflection can't fix that; it cannot know what struct a void *pNext
points to); this will require some level of manual upkeep.
Fortunately, the Vulkan XML specification description files clearly specify which structs can exist in a particular pNext
chain. So you can write a tool to load the XML, find VkPhysicalDeviceFeatures2
, and process all of the structs appearing in its pNext
chain (this part is easier said than done, since the XML format was only built to be processed by Khronos's own tools) to find which structs are available, and generate the C++ information you need. I'm sure you can write such a thing relatively easily in any scripting language.
But since you've got the struct definitions in (quasi-reasonable) XML, and you've got this tool that's going to be generating some C++ code anyway... you can just generate the actual comparison logic. That is, instead of hand-writing the member-to-member comparisons, just generate the member-to-member comparisons. You can even get the member names that don't match.
If you're going to process arbitrary pNext
-chain features, then you're going to need a generator tool of some kind. And if you're going to need a generator tool anyway, just use it to solve the whole problem.
Now, it's important to realize that the generation code for a hypothetical hasRequiredFeatures
implementation is going to have to be semi-complicated. If you're allowing a full pNext
chain of structs, then you need to build your own corresponding chain of equivalent structs to use to query from Vulkan. And that's not exactly trivial.
You will need to iterate through the pNext
chain and examine the sType
field of each struct. But of course, pNext
is a void*
, so you're going to have to lie/cheat C++'s rules a bit to read the sType
field. Basically, you'll have to reinterpret_cast
the void*
to an VkStructureType*
, read the value, compare it against all the possibilities you're working with, and proceed from there. You should skip any sType
that you don't know about, which will require doing more C++ trickery.
But you're using a low-level API; breaking C++'s rules is just a thing you'll have to get used to down here.
For each such struct, you need to allocate a matching struct, fill in its sType
appropriately, and then add it to the pNext
chain you're building.
Once you've built all of these, you can make your Vulkan call, do your comparisons, collect the data, and lastly delete the entire chain of structs.
If your goal really is to stick with just VkPhysicalDeviceFeatures
and not the extensible structs, and you just want a C++-portable way to compare such structs, then just memcpy
them into a VkBool
array and compare the two arrays for mismatches. The two types are trivially copyable, so it's not prima facie illegitmate to do this.
This code has not been compiled or tested.
bool hasRequiredFeatures(VkPhysicalDevice physical_device,
VkPhysicalDeviceFeatures required_features)
{
constexpr auto feature_count = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
using FeatureArray = std::array<VkBool, feature_count>;
auto physical_device_features = getSupportedFeatures(physical_device);
FeatureArray required;
memcpy(&required, &required_features, sizeof(FeatureArray));
FeatureArray retrieved;
memcpy(&retrieved, &physical_device_features, sizeof(FeatureArray));
bool did_mismatch = false;
for(auto it_pair = std::mismatch(required.begin(), required.end(), retrieved.begin());
it_pair.first != required.end();
it_pair = std::mismatch(it_pair.first, required.end(), it_pair.second))
{
did_mismatch = true
auto mismatch_index = it_pair.first - required.begin();
//Do something with mismatch_index
}
return did_mismatch;
}