C++自定义数学vector类vec2f转vec5f提示无合适转换报错如何解决
报错原因
- 转换构造函数的
explicit修饰符不匹配拷贝初始化语法
你定义的跨大小转换构造函数template <class U, size_t M> explicit vec(const vec<U, M>& other)加了explicit关键字,而vec<float, 5> v5 = v2;属于拷贝初始化场景,C++标准规定拷贝初始化无法调用explicit修饰的构造函数,只有直接初始化(如vec<float, 5> v5(v2))才能匹配该构造函数。 - 底层存储类型笔误
私有成员std::vector<T, N> scalars{}写法非法:std::vector的第二个模板参数是分配器类型,并非固定长度参数,你要实现固定大小的数学向量,应该用std::array<T, N>作为底层存储。 - 缺少数组越界防护
当前转换构造函数和赋值运算符没有对入参向量的长度M做约束,当M>N时,std::copy会写入越界地址,触发未定义行为。
额外问题说明:不同大小的std::array无法交换
std::array<T, 2>和std::array<T, 5>是完全无关的两个类型,C++标准库的std::swap要求两个入参是同类型,因此天生不支持交换不同大小的std::array。如果你需要支持动态大小的向量,可以放弃将长度N作为模板参数,改用std::vector<T>作为底层存储,将长度作为类的普通成员变量。
修复后的代码示例
#include <array> #include <algorithm> #include <type_traits> template <class T, size_t N, typename std::enable_if_t<(std::is_arithmetic_v<T> && N > 0), bool> = true> class vec { public: // ... template <class... U, typename std::enable_if_t<(sizeof...(U) <= N && (std::is_convertible_v<U, T> && ...)), bool> = true> explicit vec(U&&... args) : scalars({std::forward<U>(args)...}) { // 不足N的位置默认初始化 if constexpr (sizeof...(U) < N) { std::fill(scalars.begin() + sizeof...(U), scalars.end(), T{}); } } // 转换构造函数去掉explicit,增加M<=N和类型可转换约束 template <class U, size_t M, typename std::enable_if_t<(M <= N && std::is_convertible_v<U, T>), bool> = true> vec(const vec<U, M>& other) { std::copy(other.begin(), other.end(), begin()); std::fill(begin() + M, end(), T{}); } template <class U, size_t M, typename std::enable_if_t<(M <= N && std::is_convertible_v<U, T>), bool> = true> auto& operator=(const vec<U, M>& other) { // 不同模板参数的vec是不同类型,不存在自赋值风险,跳过自赋值检查 std::copy(other.begin(), other.end(), begin()); std::fill(begin() + M, end(), T{}); return *this; } // ... [[nodiscard]] constexpr auto begin() const noexcept { return scalars.begin(); } [[nodiscard]] constexpr auto begin() noexcept { return scalars.begin(); } [[nodiscard]] constexpr auto end() const noexcept { return scalars.end(); } [[nodiscard]] constexpr auto end() noexcept { return scalars.end(); } private: std::array<T, N> scalars{}; // 修正为std::array实现固定大小存储 };
修复后原测试代码可以正常编译运行,小长度向量赋值给大长度向量时,超出小向量长度的位置会自动初始化为对应类型的零值。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

