根据标准,以下代码是否正确(请注意,列表中第一个元素推导出的类型适用于第二个列表初始化元素)?

#include <type_traits>
#include <initializer_list>

struct A {};

int main()
{
    auto l = {A{}, {}};
    static_assert(std::is_same_v<std::initializer_list<A>, decltype(l)>, "!");
}

最近,我想利用 std::initializer_list 作为 Vulkan 结构的连续存储:
auto dependencies = {
    vk::SubpassDependency{
        VK_SUBPASS_EXTERNAL,
        0,
        vk::PipelineStageFlagBits::eBottomOfPipe,
        vk::PipelineStageFlagBits::eColorAttachmentOutput,
        vk::AccessFlagBits::eMemoryRead,
        vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
        vk::DependencyFlagBits::eByRegion
    },
    {
        0,
        VK_SUBPASS_EXTERNAL,
        vk::PipelineStageFlagBits::eColorAttachmentOutput,
        vk::PipelineStageFlagBits::eBottomOfPipe,
        vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
        vk::AccessFlagBits::eMemoryRead,
        vk::DependencyFlagBits::eByRegion
    }
};

并发现上述语法有效。语法比编写 std::initializer_list<vk::SubpassDependency> 而不是 auto 更简洁,但编译器是 GCC ( set(CMAKE_CXX_STANDARD 20) ),我不知道它是 GCC 特定的扩展/监督还是标准核心语言功能。

以前我认为我必须在列表初始化期间以显式方式指定所有元素的类型,才能通过 std::initializer_list 语法获得 auto x = {<list>}; 的有效初始化程序。

最佳答案

这是我阅读的标准。这里的关键是在演绎过程中



初始值设定项列表的每个元素都作为参数来推断元素类型。对于第一个,演绎成功。而其他是非推导的上下文



要使模板参数推导成功,模板参数在从不同参数推导时必须一致,只要可以从一个参数推导。如果有共识(即使只有一个),则演绎成功。



由于是非推导的上下文,尾随元素不能与从第一个元素进行的推导不一致。所以模板参数推导应该是成功的。然后,正确推导类型后,可以从相应的初始化程序对 std::initializer_list 的每个元素进行初始化。

关于c++ - 通过第一个元素推导出初始化列表的类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59455963/

10-12 13:29