模板函数返回类型推导:使用std::minus实现向量连续元素差值函数的问题
解决std::minus计算向量连续差值的模板函数返回类型推导问题
嘿,我一眼就看到你代码里的核心问题了——你把std::minus<T>这个函数对象的类型当成了运算结果的类型,这可不对!decltype(std::minus<T>())拿到的是std::minus<T>本身的类型,而不是两个T类型元素相减后的结果类型,所以你的std::vector<diffType>完全不是你想要的存储差值的容器。
我来给你修正这个问题,分不同C++版本给你靠谱的实现:
首先,理清正确的返回类型推导思路
我们需要的是**T类型元素通过std::minus<T>运算后得到的结果类型**,有几种常用的推导方式:
- 用
decltype直接推导两个T元素相减的结果:decltype(std::declval<T>() - std::declval<T>())(std::declval可以在不实例化对象的情况下拿到类型的右值引用) - C++17及以后可以用
std::invoke_result_t<std::minus<T>, T, T>,专门用来推导可调用对象的返回类型
C++11版本实现(需显式指定返回类型)
#include <vector> #include <algorithm> #include <functional> #include <utility> // 用于std::declval template <typename T> auto diffs(const std::vector<T>& nums) -> std::vector<decltype(std::declval<T>() - std::declval<T>())> { // 定义差值的类型 using DiffType = decltype(std::declval<T>() - std::declval<T>()); std::vector<DiffType> differences; // 处理边界情况:元素不足2个时直接返回空向量 if (nums.size() < 2) { return differences; } differences.reserve(nums.size() - 1); // 使用std::transform计算连续元素的差值 std::transform(std::next(nums.begin()), nums.end(), nums.begin(), std::back_inserter(differences), std::minus<T>()); return differences; }
C++14及以后版本(简化返回类型推导)
C++14支持函数返回值的自动推导,所以可以直接用auto作为返回类型,不用写尾置返回类型:
#include <vector> #include <algorithm> #include <functional> #include <utility> template <typename T> auto diffs(const std::vector<T>& nums) { using DiffType = decltype(std::declval<T>() - std::declval<T>()); std::vector<DiffType> differences; if (nums.size() < 2) { return differences; } differences.reserve(nums.size() - 1); std::transform(std::next(nums.begin()), nums.end(), nums.begin(), std::back_inserter(differences), std::minus<T>()); return differences; }
C++17版本(用std::invoke_result_t更直观)
如果你用的是C++17,用std::invoke_result_t可以更清晰地表达“推导std::minus
#include <vector> #include <algorithm> #include <functional> #include <type_traits> // 用于std::invoke_result_t template <typename T> auto diffs(const std::vector<T>& nums) { using DiffType = std::invoke_result_t<std::minus<T>, T, T>; std::vector<DiffType> differences; if (nums.size() < 2) { return differences; } differences.reserve(nums.size() - 1); std::transform(std::next(nums.begin()), nums.end(), nums.begin(), std::back_inserter(differences), std::minus<T>()); return differences; }
顺便指出原代码里的其他小问题
- 你原来写的
auto test = std::back_inserter<std::vector<decltype (std::minus<T>())>>;不仅类型错了,还少了括号——正确的用法是std::back_inserter(differences),不需要显式指定模板参数,编译器会自动推导。 - 建议用
const std::vector<T>&传递参数,避免不必要的拷贝,而且你的函数不需要修改原向量,用const更安全。 - 一定要处理向量元素少于2个的情况,否则
++begin(nums)可能会导致未定义行为。
内容的提问来源于stack exchange,提问作者Ian Lovely
相关产品推荐
相关产品推荐

