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/