代码之家  ›  专栏  ›  技术社区  ›  ModernEraCaveman

如何将模板参数与“if”和“switch”语句一起使用?

  •  2
  • ModernEraCaveman  · 技术社区  · 6 月前

    我目前正在用Vulkan用C++编写一个游戏引擎,现在我正在把我的意大利面条代码简化成更直观的东西。作为这个过程的一部分,我推广了一个描述符 struct 创建引擎所需的几个组件,以及 结构 由具有不同类型的多个对象继承。

    这不是我之间的问题 SSBO UBO 对象,因为它们都有一个成员变量 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”语句中使用模板参数?

    编辑: 我试图推广该函数的另一种方法是使用switch语句 VkDescriptorType enum :

    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;
    }
    
    1 回复  |  直到 6 月前
        1
  •  4
  •   Jan Schultke Luchian Grigore    6 月前

    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 以达到同样的效果。

    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 是一种特定的类型。