C++中创建U到V映射函数模板的惯用方法及编译问题解决
解决模板参数V无法推导的问题
你的代码报错核心原因是:模板参数V仅出现在函数返回值中,编译器无法从传入的函数参数推导它的类型——即使lambda明确返回double,C++模板推导规则也不会逆向从函数调用的返回值去匹配模板参数。
下面是几种简洁的优化方案,都能保留NRVO特性:
方案1:兼容C++11及以上的版本
利用decltype和std::declval推导映射函数的返回类型,将V替换为自动推导的类型:
#include <array> #include <utility> // 用于std::declval template <typename F, typename U, std::size_t N> auto map(F mapper, const std::array<U, N>& elements) -> std::array<decltype(mapper(std::declval<U>())), N> { using V = decltype(mapper(std::declval<U>())); std::array<V, N> newArray{}; for (std::size_t i = 0; i < N; ++i) { newArray[i] = mapper(elements[i]); } return newArray; } int main() { std::array<int, 10> ints1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; auto doubles1 = map([](int x) -> double { return x*2.5; }, ints1); }
这里decltype(mapper(std::declval<U>()))会在编译期计算出mapper接收U类型参数后的返回值类型,以此作为返回数组的元素类型,完美解决推导问题。
方案2:C++17及以上的简化版本
借助C++17的类模板推导特性,代码可以更简洁:
#include <array> template <typename F, typename U, std::size_t N> auto map(F mapper, const std::array<U, N>& elements) { using V = decltype(mapper(elements[0])); std::array<V, N> result{}; for (std::size_t i = 0; i < N; ++i) { result[i] = mapper(elements[i]); } return result; } // main函数同上
甚至可以省略using V的定义,直接在std::array中使用decltype:
std::array<decltype(mapper(elements[0])), N> result{};
为什么原代码无法编译?
C++模板参数推导的规则是:仅从函数的实参推导模板参数,而你的原代码中V只出现在返回值的std::array<V, N>里,没有任何传入的参数类型包含V,因此编译器无法推断V的具体类型,只能报错。
两种方案都保留了NRVO优化:函数返回的局部数组对象会被编译器直接构造在调用方的栈空间中,不会产生额外的拷贝开销。
内容的提问来源于stack exchange,提问作者lucas
相关产品推荐
相关产品推荐

