第8.5.4/7节中的标准解释了缩小转换的含义:
缩小转换是隐式转换
- 从浮点类型到整数类型,或
- 从long double到double或float,或从double到float,除非source是常量表达式,转换后的实际值在可以表示的值范围内(即使它不能精确表示),或者
- 从整数类型或无范围枚举类型到浮点类型,除非源是常量表达式,转换后的实际值将适合目标类型,并在转换回原始类型时生成原始值,要么
- 从整数类型或未范围的枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式,并且转换后的实际值将适合目标类型并将生成原始值转换回原始类型时.
然后它在一些列表初始化上下文中不允许这样的转换,给出了示例:
[注意:如上所述,列表初始化中的顶层不允许进行此类转换. - 尾注] [示例:
int x = 999; // x is not a constant expression
const int y = 999;
const int z = 99;
char c1 = x; // OK, though it might narrow (in this case, it does narrow)
char c2{x}; // error: might narrow
char c3{y}; // error: narrows (assuming char is 8 bits)
char c4{z}; // OK: no narrowing needed
unsigned char …Run Code Online (Sandbox Code Playgroud) 为什么这会给出编译时错误?2在编译时是恒定的,因此这里应允许缩小,因为2在字节范围内.
public class Test {
public static void main(String[] args) {
ForTest test=new ForTest();
test.sum(1, 2); //compile time error here
}
}
class ForTest
{
public int sum(int a,byte b)
{
System.out.println("method byte");
return a+b;
}
}
Run Code Online (Sandbox Code Playgroud)
错误是:ForTest类型中的方法sum(int,byte)不适用于arguements(int,int).
编辑:我认为答案就在这里:http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.3但我没有得到它:(
考虑以下代码:
#include <cstdint>
class A
{
public:
explicit A(uint8_t p_a){ m_a = p_a; };
uint8_t get_a() const {return m_a;}
private:
uint8_t m_a;
};
int main()
{
A a {0x21U};
A aa{0x55U};
uint8_t mask{a.get_a() | aa.get_a()};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译this(gcc 5.4.0)时,我收到以下错误:
main.cpp: In function ‘int main()’:
main.cpp:20:28: warning: narrowing conversion of ‘(int)(a.A::get_a() | aa.A::get_a())’ from ‘int’ to ‘uint8_t {aka unsigned char}’ inside { } [-Wnarrowing]
uint8_t mask{a.get_a() | aa.get_a()};
Run Code Online (Sandbox Code Playgroud)
我真的不明白为什么会有任何缩小.该int类型从未在我的代码中的任何地方使用过,所有内容都是用unsigned chars语言编写的.即使我明确地转向unsigned char我得到错误:
uint8_t …Run Code Online (Sandbox Code Playgroud) 使用P0960 “允许从带括号的值列表中初始化聚合”时,也可以使用()s 进行聚合init 。
但是,此初始化允许缩小,而{}s不允许。
#include <vector>
#include <climits>
struct Foo
{
int x, y;
};
int main()
{
// auto p = new Foo{INT_MAX, UINT_MAX}; // still won't compile
auto q = new Foo(INT_MAX, UINT_MAX); // c++20 allows narrowing aggregates init
std::vector<Foo> v;
// v.emplace_back(Foo{INT_MAX, UINT_MAX}); // still won't compile
v.emplace_back(INT_MAX, UINT_MAX); // c++20 allows narrowing aggregates init
// in furtherly perfect forwardings
}
Run Code Online (Sandbox Code Playgroud)
是否可以使用带括号的C ++ 20聚合初始化来检测变窄的转换?
为什么会有警告
缩小从 char 到 double 的转换
我已经知道对于 const char 不会有警告。有很多关于这个的答案。但我想知道,为什么非常量字符会有“可能缩小”的警告?
在某些系统上,尾数是否可能不足以完美表示字符?
int main() {
char c{7};
double a{c};
}
Run Code Online (Sandbox Code Playgroud)
4:13:警告:在 { } [-Wnarrowing] 中缩小从 'char' 到 'double' 的 'c' 转换
当我尝试编译这段代码时
struct T
{
unsigned char x;
};
int main()
{
unsigned char a = 10;
unsigned char b = 1;
T t = {a + b};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
错误:在 { } [-Wnarrowing]| 内将 '(((int)a) + ((int)b))' 从 'int' 缩小转换为 'unsigned char'
谁能解释一下为什么?
我一直在读一本书(C++ 编程语言 Stroustrup 第 4 版)。与初始化相关的部分中给出的示例如下:
void f(double d, int i)
{
int a{ d }; // error : possible truncation
char b{ i }; // error : possible narrowing
}
Run Code Online (Sandbox Code Playgroud)
截断和缩小之间究竟有什么区别?
每个 C++ 教程早期都会提到两件事:
int narrow{1.7}; // error: narrowing conversion of '1.7e+0' from 'double' to 'int'
Run Code Online (Sandbox Code Playgroud)
float some_float{1.7f};
Run Code Online (Sandbox Code Playgroud)
然而,当在 Windows 上使用 g++ 编译器时,我发现了一些奇怪的事情 -
float narrow{1.7}; // still a float despite no f postfix
double not_narrow{1.7}; // actually a double
Run Code Online (Sandbox Code Playgroud)
此代码编译时没有任何错误,并sizeof(narrow)返回 4,其中sizeof(not_narrow)返回 8,正如预期的那样。
将鼠标悬停在 1.7 上时,VSCode 将其识别为双精度文字 ~=1.699999999999999956,但 float 随后将其缩小到 ~=1.700000048。
我认为这可能只是 1.7 作为浮点数和双精度数都有效,所以我尝试了
float narrow{1.699999999999999956};
Run Code Online (Sandbox Code Playgroud)
但这会产生相同的结果。
为什么花括号初始化不会在这里抛出错误(警告,诊断消息,任何东西)来将双精度文字缩小为浮点数?这是 g++ 特有的,还是 C++ 的一般怪癖?我很想更好地理解。
假设我在一个名为'array'的数组中有这个列表:
[0]a.1
[1]b.1
[2]c.1
[3]d.1
[4]e.2
[5]f.2
[6]g.2
[7]h.3
Run Code Online (Sandbox Code Playgroud)
我想用C#将它缩小到一个列表中最多有两个相同数字的列表,所以它看起来像这样:
[0]a.1
[1]b.1
[2]e.2
[3]f.2
[4]h.3
Run Code Online (Sandbox Code Playgroud)
我试图使用'GroupBy':
var Groups = array.GroupBy(i => i);
var Result = Groups.SelectMany(iGroup => iGroup.Take(2)).ToArray();
Run Code Online (Sandbox Code Playgroud)
但我不确定如何只考虑点后的内容,而不是整个项目
请考虑以下代码,说明一些缩小的转换:
template <class T>
class wrapper
{
template <class> friend class wrapper;
public:
constexpr wrapper(T value)
: _data(value)
{}
template <class U>
constexpr wrapper(wrapper<U> other)
: _data(other._data)
{}
wrapper& operator=(T value)
{_data = value; return *this;}
template <class U>
wrapper& operator=(wrapper<U> other)
{_data = other._data; return *this;}
private:
T _data;
};
int main(int argc, char* argv[])
{
wrapper<unsigned char> wrapper1 = 5U;
wrapper<unsigned char> wrapper2{5U};
wrapper<unsigned char> wrapper3(5U);
wrapper<unsigned int> wrapper4 = 5U;
wrapper<unsigned int> wrapper5{5U};
wrapper<unsigned int> wrapper6(5U);
wrapper<unsigned …Run Code Online (Sandbox Code Playgroud)