初始化程序列表中的非常量表达式不能从类型'int'缩小为'unsigned long long' [英] non-constant-expression cannot be narrowed from type 'int' to 'unsigned long long' in initializer list

查看:49
本文介绍了初始化程序列表中的非常量表达式不能从类型'int'缩小为'unsigned long long'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

int main(int argc, char const *argv[])
{
   int x =  4;
   int y = 2;
   const int cell = x/y;
   auto a = std::bitset<20>{cell}; //fails
   auto b = std::bitset<20>(cell); //works
}

为什么 std :: bitset 不允许在这里使用花括号进行构建,但是可以在括号结构中进行构建?如果 cell constexpr ,则两者都可以编译.

Why does std::bitset not allow me to construct with curly braces here, but works with parenthesis construction? If cell was instead a constexpr, both would compile.

编译错误:

test.cpp:21:29: error: non-constant-expression cannot be narrowed from type 'int' to 'unsigned long long' in initializer list [-Wc++11-narrowing]
   auto a = std::bitset<20>{x*y}; //fails
                            ^~~
test.cpp:21:29: note: insert an explicit cast to silence this issue
   auto a = std::bitset<20>{x*y}; //fails
                            ^~~
                            static_cast<unsigned long long>( )
1 error generated.

推荐答案

失败的行使用列表初始化语法:

The failing line uses list-initializing syntax:

auto a = std::bitset<20>{cell}; //fails

此语法在 C ++ 17标准的第11.6.4节.相关部分:

对象或类型为 T 的引用的列表初始化定义如下:

List-initialization of an object or reference of type T is defined as follows:

...

(3.7)否则,如果 T 是类类型,则考虑构造函数.列举了适用的构造函数,并通过重载分辨率(16.3,16.3.1.7)选择了最佳的构造函数.如果要转换任何参数需要缩小转换(见下文),则程序格式错误.

(3.7) Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (16.3, 16.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

...

缩小转换是隐式转换

...

(7.4)从整数类型或非范围枚举类型到不能表示原始类型的所有值的整数类型,,除非源是一个常量表达式,其整数提升后的值将适合目标输入.

(7.4) from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.

这使我们对发生的事情有了更好的了解:

This gives us a better understanding of what is going on:

// Works, no narrowing check, implicit conversion.
std::bitset<20> a(2);
std::bitset<20> b(-1);
std::bitset<20> c(cell); 

// Works, 2 can be converted without narrowing
std::bitset<20> d{2};

// Fails, -1 cannot be converted without narrowing
std::bitset<20> e{-1};

// Fails, compiler does not understand cell can be converted without narrowing
std::bitset<20> f{cell};

在您的程序中,编译器无法理解 cell 是一个常量表达式.它检查 std :: bitset 的可用构造函数,并查看它是否必须从 int 转换为 unsigned long long .它认为 int 可能为负,因此我们的转换范围越来越窄.

In your program, the compiler does not understand that cell is a constant expression. It checks the available constructors for std::bitset and sees it has to convert from int to unsigned long long. It thinks that int could be potentially be negative, therefore we have a narrowing conversion.

我们可以通过将 cell 设置为 constexpr 来解决此问题,它比 const 更强.而 const 仅表示不应更改该值,而 constexpr 则表示该值在编译时可用:

We can fix this by making cell a constexpr, which is stronger than const. Whereas const only means that the value should not be changed, constexpr means the value is available at compile time:

  constexpr int x = 4;
  constexpr int y = 2;
  constexpr int cell = x / y;

  auto a = std::bitset<20>{cell}; // works

您现在可以问为什么列表初始化不允许缩小转换范围.我无法完全回答.我的理解是,隐式缩小通常被认为是不可取的,因为它可能会产生意想不到的后果,并且出于这个原因而被排除在外.

You could now ask why list-initialization does not allow for narrowing conversion. I cannot fully answer this. My understanding is that implicit narrowing is generally seen as undesirable because it can have unintended consequences, and that it was excluded for this reason.

这篇关于初始化程序列表中的非常量表达式不能从类型'int'缩小为'unsigned long long'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆