c++ 如何在“if”和“switch”语句中使用模板参数?

mwg9r5ms  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(120)

我目前正在用Vulkan用C++写一个游戏引擎,现在我正在把我的意大利面条代码简化成更直观的东西。作为这个过程的一部分,我一般化了一个描述符struct来创建引擎所需的几个组件,struct由几个不同类型的对象继承。
这在我的SSBOUBO对象之间不是问题,因为它们都有一个VkDescriptorBufferInfo类型的成员变量。但是,我的Texture对象的不同之处在于成员变量是VkDescriptorImageInfo类型。
这两种类型由VkWriteDescriptorSet对象使用,其在“vulkan_core.h”头中的定义是:

typedef struct VkWriteDescriptorSet {
    VkStructureType                  sType;
    const void*                      pNext;
    VkDescriptorSet                  dstSet;
    uint32_t                         dstBinding;
    uint32_t                         dstArrayElement;
    uint32_t                         descriptorCount;
    VkDescriptorType                 descriptorType;
    const VkDescriptorImageInfo*     pImageInfo;   //to be provided by my Texture objects
    const VkDescriptorBufferInfo*    pBufferInfo;  //to be provided by my UBO/SSBO objects
    const VkBufferView*              pTexelBufferView;
} VkWriteDescriptorSet;

字符串
我尝试一般化VkWriteDescriptorSet对象的创建,如下所示:

template <typename T>
inline VkWriteDescriptorSet writeSet(const std::vector<T>& bufferInfo, std::array<size_t,2> dst) {
    VkWriteDescriptorSet writeInfo { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };

    /* Here I try to differentiate how the VkWriteDescriptorSet object is created */
    if (std::is_same<T, VkDescriptorImageInfo>::value) {
        writeInfo.pImageInfo = &bufferInfo[dst[1]];  //requires T == VkDescriptorImageInfo
    }
    else {
        writeInfo.pBufferInfo = &bufferInfo[dst[1]]; //requires T == VkDescriptorBufferInfo
    }

    /* Then the function fills out the rest of the object */

    return writeInfo;
}


在下面的函数中调用上述函数:

void writeSets(uint32_t bindingCount) {    
    // The type of the vector below depends on the calling object (UBO/SSBO or Texture)
    std::vector</* VkDescriptorBufferInfo or VkDescriptorImageInfo */> bufferInfo(bindingCount);

    std::vector<VkWriteDescriptorSet> descriptorWrites(bindingCount);
    for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {           
        /* loop does stuff */
        for (size_t j = 0; j < bindingCount; j++) {
            /* loop does more stuff */
            descriptorWrites[j] = writeSet(bufferInfo, { i, j }); // the generalized function is called
        }
        vkUpdateDescriptorSets(VkGPU::device, bindingCount, descriptorWrites.data(), 0, nullptr);
    }
}


不幸的是,我的程序将无法编译并返回以下错误:

Severity: Error
Line: 27
Code: C2440
Description: '=': cannot convert from 'const _Ty *' to 'const VkDescriptorImageInfo *'


最后,这就引出了我的问题,如何在“if”和“switch”语句中使用模板参数?
编辑:我尝试泛化该函数的其他方法之一是使用VkDescriptorTypeenum的switch语句:

template <typename T>
inline VkWriteDescriptorSet writeSet(const std::vector<T>& bufferInfo, std::array<size_t,2> dst) {
    VkWriteDescriptorSet writeInfo { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };

    /* Here I try to differentiate how the VkWriteDescriptorSet object is created */
    switch (type) {
    case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
        writeInfo.pImageInfo = &bufferInfo[dst[1]];  //requires T == VkDescriptorImageInfo
    default:
        writeInfo.pBufferInfo = &bufferInfo[dst[1]]; //requires T == VkDescriptorBufferInfo
    }

    /* Then the function fills out the rest of the object */

    return writeInfo;
}

0aydgbwb

0aydgbwb1#

C++17

如果你使用的是C++17,解决方案很简单。您可以将if转换为if constexpr

VkWriteDescriptorSet writeInfo { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };

if constexpr (std::is_same_v<T, VkDescriptorImageInfo>) {
    writeInfo.pImageInfo = &bufferInfo[dst[1]];
}
else {
    // Optional assertion; ensures that were aren't working with some third type.
    // This also documents our type expectation.
    static_assert(std::is_same_v<T, VkDescriptorBufferInfo>);
    writeInfo.pBufferInfo = &bufferInfo[dst[1]];
}

字符串
请注意,没有switch constexpr这样的东西,但是,您可以简单地编写一长串if constexpr ... else if constexpr语句来实现相同的效果。

Pre-C++17

在C++17之前,你可以简单地写两个重载:

inline VkWriteDescriptorSet writeSet(const std::vector<VkDescriptorImageInfo>& bufferInfo,
                                     std::array<size_t,2> dst) {
    /* ... */
}

inline VkWriteDescriptorSet writeSet(const std::vector<VkDescriptorBufferInfo>& bufferInfo,
                                     std::array<size_t,2> dst) {
    /* ... */
}


没有太多的代码重复,所以在这种情况下应该没问题。如果函数比较大,可以考虑模板的完全或部分专门化等解决方案,只针对不同的部分,并取决于T是否是特定类型。

相关问题