std::setw() 和 ostream::width() 之间的类型不一致
type inconsistency between std::setw() and ostream::width()
这个简单的代码
template<typename T>
std::ostream&operator<<(std::ostream&s, some_array_type<T> const&x)
{
auto w = s.width();
auto p = s.precision();
s << x[0];
for(std::size_t i=1; i!=x.size(); ++i)
s << ' ' << std::setw(w) << std::setprecision(p) << m[i];
return s;
}
打算打印一个 some_array_type
每个元素的宽度和精度等于当前值,允许像
这样的代码
some_array_type<double> x;
std::cout << std::setw(12) << std::setprecision(8) << x << std::endl;
然而,正如 clang 指出的那样,ostream::width()
和 ostream::precision()
(std::size_t
) 返回的类型不同于操纵器 std::setw
和 std::setprecision
(int
),这样上面的代码会触发两个警告。
这种不一致是否有特殊原因,或者这只是 C++ 标准中的一个小缺陷(或 libc++ 实现的错误)?
首先,这显然是实施中的一个错误。标准说
std::ios_base::width
和 std::ios_base::precision
使用
std::streamsize
,要求是“signed basic”
整数类型”——在现代系统中,我希望 long long
,或者可能 long
。 std::size_t
要求无符号,
并且可以说也不是 "basic integral type" (尽管它可能是
一个类型定义)。
事实仍然是成员函数 std::ios_base::width
和
std::ios_base::precision
可能(并且很可能会)使用不同的类型
比操纵器(总是 int
)。而如果
std::streamsize
是 long long
,它的某些值不会
适合 int
。这样一个值实际出现的概率
正确的代码对我来说似乎很小,我会坚持下去
int
(而不是混淆 auto
),并且不用担心风险
溢出。或者,我会使用 int
,但之前使用 assert
,以
确保没有溢出。
最后:通常情况下,宽度是元素的总宽度。所以
您应该设置的宽度是 w / x.size() - 1
(包括
第一个元素)。至少在理论上;我不确定这对
数组类型(我当然不会坚持,只要
修改后的语义有据可查)。当然,精度是
黏;您不必为每个值都设置它。 (另一方面,
用户应该记住并恢复它。)
这个简单的代码
template<typename T>
std::ostream&operator<<(std::ostream&s, some_array_type<T> const&x)
{
auto w = s.width();
auto p = s.precision();
s << x[0];
for(std::size_t i=1; i!=x.size(); ++i)
s << ' ' << std::setw(w) << std::setprecision(p) << m[i];
return s;
}
打算打印一个 some_array_type
每个元素的宽度和精度等于当前值,允许像
some_array_type<double> x;
std::cout << std::setw(12) << std::setprecision(8) << x << std::endl;
然而,正如 clang 指出的那样,ostream::width()
和 ostream::precision()
(std::size_t
) 返回的类型不同于操纵器 std::setw
和 std::setprecision
(int
),这样上面的代码会触发两个警告。
这种不一致是否有特殊原因,或者这只是 C++ 标准中的一个小缺陷(或 libc++ 实现的错误)?
首先,这显然是实施中的一个错误。标准说
std::ios_base::width
和 std::ios_base::precision
使用
std::streamsize
,要求是“signed basic”
整数类型”——在现代系统中,我希望 long long
,或者可能 long
。 std::size_t
要求无符号,
并且可以说也不是 "basic integral type" (尽管它可能是
一个类型定义)。
事实仍然是成员函数 std::ios_base::width
和
std::ios_base::precision
可能(并且很可能会)使用不同的类型
比操纵器(总是 int
)。而如果
std::streamsize
是 long long
,它的某些值不会
适合 int
。这样一个值实际出现的概率
正确的代码对我来说似乎很小,我会坚持下去
int
(而不是混淆 auto
),并且不用担心风险
溢出。或者,我会使用 int
,但之前使用 assert
,以
确保没有溢出。
最后:通常情况下,宽度是元素的总宽度。所以
您应该设置的宽度是 w / x.size() - 1
(包括
第一个元素)。至少在理论上;我不确定这对
数组类型(我当然不会坚持,只要
修改后的语义有据可查)。当然,精度是
黏;您不必为每个值都设置它。 (另一方面,
用户应该记住并恢复它。)