自定义二维向量的适当大小初始化 class
Proper size initialization of a custom two dimensional vector class
我正在尝试编写自己的 Vector2D
class,但当我尝试初始化 Vector2D
的大小时 运行 遇到了问题构造函数。
#include <vector>
template <typename T>
class Vector2D
{
public:
explicit Vector2D(const size_t& rows, const size_t& columns)
: m_data(rows, std::vector<T>{ columns })
{}
private:
std::vector<std::vector<T>> m_data;
};
int main()
{
// Compiles fine
std::vector<std::vector<float>> v1{ 10, std::vector<float>{ 10 }};
// Results in narrowing conversion warnings!
Vector2D<float> v2{ 10, 10 };
}
在main
的第一行我可以轻松地初始化一个二维向量并设置两个维度的大小。
在下一行中,我尝试通过 Vector2D
的构造函数做完全相同的事情,但出于某种原因,我收到了有关缩小转换的警告!
<source>: In instantiation of 'Vector2D<T>::Vector2D(const size_t&, const size_t&) [with T = float; size_t = long unsigned int]':
<source>:21:32: required from here
<source>:8:49: warning: narrowing conversion of '(size_t)columns' from 'size_t' {aka 'long unsigned int'} to 'float' [-Wnarrowing]
8 | : m_data(rows, std::vector<T>{ columns })
| ^
<source>:8:49: warning: narrowing conversion of 'columns' from 'const size_t' {aka 'const long unsigned int'} to 'float' [-Wnarrowing]
由于 Vector2D
构造函数基本上与编译良好的行完全相同,为什么会导致编译器警告?
这个警告实际上非常有用,如果你打印由此产生的矢量,你会看到这个
#include <iostream>
#include <vector>
template <typename T> class Vector2D {
public:
explicit Vector2D(const size_t &rows, const size_t &columns)
: m_data(rows, std::vector<T>{columns, 0}) {}
void print() {
for (auto vec : m_data) {
for (auto val : vec)
std::cout << val << ' ';
std::cout << ',';
}
}
private:
std::vector<std::vector<T>> m_data;
};
int main() {
Vector2D<float> v2{10, 10};
v2.print();
}
./a.out
10 0
10 0
10 0
10 0
10 0
10 0
10 0
10 0
10 0
10 0
这是由于从 size_t 到 float 的缩小转换导致的 initializer_list 构造函数 vector
要解决此问题,您需要将大括号{}替换为括号(),如此处所示
#include <iostream>
#include <vector>
template <typename T> class Vector2D {
public:
explicit Vector2D(const size_t &rows, const size_t &columns)
: m_data(rows, std::vector<T>(columns)) {}
private:
std::vector<std::vector<T>> m_data;
};
int main() {
Vector2D<float> v2{10, 10};
v2.print();
}
警告告诉了您需要知道的一切,您选择忽略它。这是你的构造函数。
explicit Vector2D(const size_t& rows, const size_t& columns)
: m_data(rows, std::vector<T>{ columns })
{}
初始化部分使用 std::vector
的 std::initializer_list
构造函数创建行 x 1 二维向量,其中每个行向量都有其唯一元素初始化为 columns
,这是一个 std::size_t
,这导致从 std::size_t
到 float
的缩小警告。它使用 std::initializer_list
构造函数,因为您使用的是花括号初始化。就这么简单。
解决方法是通过在初始化部分的构造函数调用中将大括号初始化 {}
更改为 ()
来简单地调用正确的构造函数。
关于为什么在 main()
中声明标准 2D 向量时没有出现错误。也是一样的道理。测试它就像打印尺寸一样简单。
#include <vector>
#include <iostream>
int main()
{
// Compiles fine
std::vector<std::vector<float>> v1{ 10, std::vector<float>{ 10 }};
for (auto vec : v1) {
std::cout << vec.size() << '\n';
}
这会打印:
1
1
1
1
1
1
1
1
1
1
您创建了一个 10x1 二维矢量,因为您传递了 std::initializer_list
。这就是为什么它很可能没有按照您的想法行事。文字 10
也是一个 int,将它转换为 float 不会引发警告,因为这两种类型在您的系统上可能大小相同,并且您明确地将 10 放在那里,这会消除缩小警告.测试完全相同的逻辑会导致完全相同的错误,如 here:
所示
#include <vector>
int main()
{
std::size_t val = 10;
std::vector<std::vector<float>> v1{ 10, std::vector<float>{ val }};
}
如果您尝试用 std::size_t(10)
代替 val
,它会消除警告,但您仍然缩小了数据范围。编译器只是假定您现在打算这样做,因为它已明确完成。
这是您的代码,已修复:
#include <vector>
#include <iostream>
template <typename T>
class Vector2D
{
public:
explicit Vector2D(const size_t& rows, const size_t& columns)
: m_data(rows, std::vector<T>(columns)) // Only changed {} to ()
{}
// private: // For ease of testing
std::vector<std::vector<T>> m_data;
};
int main()
{
Vector2D<float> v2{ 10, 10 };
for (auto vec : v2.m_data) {
std::cout << vec.size() << '\n';
}
}
由于您的 class 没有提供 std::initializer_list
构造函数,因此您不必为 Vec2D
担心。 But std::vector
does(#10 in the list), and you kept invoking them, and then insisting that you weren't. Unlike the other answer, I am opting to not provide a default value in your Vec2D
constructor, meaning that the Vec2D
object will instantiated with values of T()
, which will always work if T
is DefaultConstructable。对于任何不能用 0 值初始化的 class,另一个答案立即中断,这不是一个小数字。
在未来,如果您倾听别人告诉您的内容而不是顶撞,那么对于所有相关人员来说都会容易得多。你是那个破坏代码的人,这个网站上没有人欠你任何东西。
我正在尝试编写自己的 Vector2D
class,但当我尝试初始化 Vector2D
的大小时 运行 遇到了问题构造函数。
#include <vector>
template <typename T>
class Vector2D
{
public:
explicit Vector2D(const size_t& rows, const size_t& columns)
: m_data(rows, std::vector<T>{ columns })
{}
private:
std::vector<std::vector<T>> m_data;
};
int main()
{
// Compiles fine
std::vector<std::vector<float>> v1{ 10, std::vector<float>{ 10 }};
// Results in narrowing conversion warnings!
Vector2D<float> v2{ 10, 10 };
}
在main
的第一行我可以轻松地初始化一个二维向量并设置两个维度的大小。
在下一行中,我尝试通过 Vector2D
的构造函数做完全相同的事情,但出于某种原因,我收到了有关缩小转换的警告!
<source>: In instantiation of 'Vector2D<T>::Vector2D(const size_t&, const size_t&) [with T = float; size_t = long unsigned int]':
<source>:21:32: required from here
<source>:8:49: warning: narrowing conversion of '(size_t)columns' from 'size_t' {aka 'long unsigned int'} to 'float' [-Wnarrowing]
8 | : m_data(rows, std::vector<T>{ columns })
| ^
<source>:8:49: warning: narrowing conversion of 'columns' from 'const size_t' {aka 'const long unsigned int'} to 'float' [-Wnarrowing]
由于 Vector2D
构造函数基本上与编译良好的行完全相同,为什么会导致编译器警告?
这个警告实际上非常有用,如果你打印由此产生的矢量,你会看到这个
#include <iostream>
#include <vector>
template <typename T> class Vector2D {
public:
explicit Vector2D(const size_t &rows, const size_t &columns)
: m_data(rows, std::vector<T>{columns, 0}) {}
void print() {
for (auto vec : m_data) {
for (auto val : vec)
std::cout << val << ' ';
std::cout << ',';
}
}
private:
std::vector<std::vector<T>> m_data;
};
int main() {
Vector2D<float> v2{10, 10};
v2.print();
}
./a.out
10 0
10 0
10 0
10 0
10 0
10 0
10 0
10 0
10 0
10 0
这是由于从 size_t 到 float 的缩小转换导致的 initializer_list 构造函数 vector
要解决此问题,您需要将大括号{}替换为括号(),如此处所示
#include <iostream>
#include <vector>
template <typename T> class Vector2D {
public:
explicit Vector2D(const size_t &rows, const size_t &columns)
: m_data(rows, std::vector<T>(columns)) {}
private:
std::vector<std::vector<T>> m_data;
};
int main() {
Vector2D<float> v2{10, 10};
v2.print();
}
警告告诉了您需要知道的一切,您选择忽略它。这是你的构造函数。
explicit Vector2D(const size_t& rows, const size_t& columns)
: m_data(rows, std::vector<T>{ columns })
{}
初始化部分使用 std::vector
的 std::initializer_list
构造函数创建行 x 1 二维向量,其中每个行向量都有其唯一元素初始化为 columns
,这是一个 std::size_t
,这导致从 std::size_t
到 float
的缩小警告。它使用 std::initializer_list
构造函数,因为您使用的是花括号初始化。就这么简单。
解决方法是通过在初始化部分的构造函数调用中将大括号初始化 {}
更改为 ()
来简单地调用正确的构造函数。
关于为什么在 main()
中声明标准 2D 向量时没有出现错误。也是一样的道理。测试它就像打印尺寸一样简单。
#include <vector>
#include <iostream>
int main()
{
// Compiles fine
std::vector<std::vector<float>> v1{ 10, std::vector<float>{ 10 }};
for (auto vec : v1) {
std::cout << vec.size() << '\n';
}
这会打印:
1
1
1
1
1
1
1
1
1
1
您创建了一个 10x1 二维矢量,因为您传递了 std::initializer_list
。这就是为什么它很可能没有按照您的想法行事。文字 10
也是一个 int,将它转换为 float 不会引发警告,因为这两种类型在您的系统上可能大小相同,并且您明确地将 10 放在那里,这会消除缩小警告.测试完全相同的逻辑会导致完全相同的错误,如 here:
#include <vector>
int main()
{
std::size_t val = 10;
std::vector<std::vector<float>> v1{ 10, std::vector<float>{ val }};
}
如果您尝试用 std::size_t(10)
代替 val
,它会消除警告,但您仍然缩小了数据范围。编译器只是假定您现在打算这样做,因为它已明确完成。
这是您的代码,已修复:
#include <vector>
#include <iostream>
template <typename T>
class Vector2D
{
public:
explicit Vector2D(const size_t& rows, const size_t& columns)
: m_data(rows, std::vector<T>(columns)) // Only changed {} to ()
{}
// private: // For ease of testing
std::vector<std::vector<T>> m_data;
};
int main()
{
Vector2D<float> v2{ 10, 10 };
for (auto vec : v2.m_data) {
std::cout << vec.size() << '\n';
}
}
由于您的 class 没有提供 std::initializer_list
构造函数,因此您不必为 Vec2D
担心。 But std::vector
does(#10 in the list), and you kept invoking them, and then insisting that you weren't. Unlike the other answer, I am opting to not provide a default value in your Vec2D
constructor, meaning that the Vec2D
object will instantiated with values of T()
, which will always work if T
is DefaultConstructable。对于任何不能用 0 值初始化的 class,另一个答案立即中断,这不是一个小数字。
在未来,如果您倾听别人告诉您的内容而不是顶撞,那么对于所有相关人员来说都会容易得多。你是那个破坏代码的人,这个网站上没有人欠你任何东西。