如何在不指定模板参数的前提下,以nullptr作为首元素初始化std::array
我完全懂你现在的困扰——clang-tidy逼着你弃用C数组转用std::array,但当首元素是nullptr时自动推导直接翻车,又不想手动敲那一大串长指针类型名,实在太麻烦了。
先给你理清楚问题根源:std::array的类模板实参推导(CTAD)默认会以初始化列表第一个元素的类型作为数组的元素类型。当你把nullptr放第一个,编译器会把数组类型推导成std::nullptr_t,可后面的ID3D11ShaderResourceView*根本没法隐式转换成std::nullptr_t,自然就报类型不匹配的错了。
接下来给你几个不用显式写std::array<ID3D11ShaderResourceView*, 15>的解决方案:
方案1:用decltype推导目标类型,转换第一个nullptr
这个方法不用手动拼写长类型名,而是让编译器从后面的有效指针元素自动推导类型,再把第一个nullptr转成该类型:
std::array srvs = { static_cast<decltype(lightmap_srv.Get())>(nullptr), // 用decltype从后续元素拿目标类型 lightmap_srv.Get(), room_normal_srv.Get(), nullptr, // 后面的nullptr会自动转成目标指针类型 nullptr, nullptr, nullptr, nullptr, nullptr, input.ambient_occlusion, reflection_srv.Get(), reflection_extents_srv.Get(), nullptr, nullptr, nullptr };
这里decltype(lightmap_srv.Get())会自动推导出ID3D11ShaderResourceView*,完全满足“不指定模板参数”的要求。
方案2:自己写个简单的辅助推导函数
如果你的代码里经常需要这种初始化场景,可以写一个轻量工具函数,让编译器自动推导所有元素的公共类型:
#include <type_traits> #include <array> template <typename... Ts> auto make_array(Ts&&... ts) -> std::array<std::common_type_t<Ts...>, sizeof...(Ts)> { return {std::forward<Ts>(ts)...}; }
之后用这个函数初始化数组,完全不用操心类型推导的问题:
auto srvs = make_array( nullptr, lightmap_srv.Get(), room_normal_srv.Get(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, input.ambient_occlusion, reflection_srv.Get(), reflection_extents_srv.Get(), nullptr, nullptr, nullptr );
std::common_type_t<Ts...>会自动找出所有元素都能转换的公共类型——这里就是ID3D11ShaderResourceView*,完美适配你的场景。
方案3:用C++20的std::make_array(如果环境支持)
如果你的编译器支持C++20,标准库自带的std::make_array已经帮你处理了这种类型推导场景,直接用就行:
#include <array> auto srvs = std::make_array( nullptr, lightmap_srv.Get(), room_normal_srv.Get(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, input.ambient_occlusion, reflection_srv.Get(), reflection_extents_srv.Get(), nullptr, nullptr, nullptr );
std::make_array会自动推导所有元素的兼容公共类型,省去自己写辅助函数的麻烦。
备注:内容来源于stack exchange,提问作者Raildex

