c++ - 初始化程序列表中的非常量表达式不能从 'int'类型缩小为 'unsigned long long'

标签 c++ constructor bitset

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,则两者都将编译。

编译错误:
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.

最佳答案

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

auto a = std::bitset<20>{cell}; //fails
该语法在C++ 17标准的Section 11.6.4中定义。相关部分:

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

...

(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.

...

A narrowing conversion is an implicit conversion

...

(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.


这使我们对发生的事情有了更好的了解:
// 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可能为负,因此我们的转换范围越来越窄。
我们可以通过将cell设置为比constexpr更强的const来解决此问题。 const仅表示不应更改该值,而constexpr表示该值在编译时可用:
  constexpr int x = 4;
  constexpr int y = 2;
  constexpr int cell = x / y;

  auto a = std::bitset<20>{cell}; // works
您现在可以问为什么列表初始化不允许缩小转换范围。我无法完全回答。我的理解是,通常认为隐式收窄是不希望的,因为它可能产生意想不到的后果,并且出于这个原因而被排除在外。

关于c++ - 初始化程序列表中的非常量表达式不能从 'int'类型缩小为 'unsigned long long',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60368422/

相关文章:

c++ - 这是通过引用传递文件指针的正确语法吗?

c++ - C++中的构造函数中的枚举

java - 如何让BitSet不被简化【JAVA】

memory - Scala 中的 BitSet 内存使用情况

c++ - 从 C++ QML 类型访问 QML 根对象

c++ - 约束编辑控件内容

c++ - 这是部分模板特化吗?

c++ - 如何将用户输入存储在与默认构造函数中的变量初始化值不同的变量中?

java - Scala 方式来初始化成员?

c++ - std::string 到 std::bitset 由 std::string 表示,反之亦然