Iam*_*non 6 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
}
Run Code Online (Sandbox Code Playgroud)
为什么不允许std::bitset我在这里使用花括号构建,但可以使用括号构建?如果cell是 a 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.
Run Code Online (Sandbox Code Playgroud)
失败的行使用列表初始化语法:
auto a = std::bitset<20>{cell}; //fails
Run Code Online (Sandbox Code Playgroud)
此语法在C++17 标准的第 11.6.4 节中定义。相关部分:
对象或类型引用的列表初始化
T定义如下:...
(3.7) 否则,如果
T是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决策选择最好的构造函数(16.3、16.3.1.7)。如果需要缩小转换(见下文)来转换任何参数,则该程序格式错误。...
缩小转换是隐式转换
...
(7.4) 从整数类型或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式,其整型提升后的值将适合目标类型。
这让我们更好地了解正在发生的事情:
// 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};
Run Code Online (Sandbox Code Playgroud)
在您的程序中,编译器不理解这cell是一个常量表达式。它检查可用的构造函数std::bitset并发现它必须从 转换int为unsigned long long。它认为这int可能是负数,因此我们的转换范围缩小。
我们可以通过创建cella来解决这个问题constexpr,它比 更强const。而constonly 表示该值不应更改,constexpr表示该值在编译时可用:
constexpr int x = 4;
constexpr int y = 2;
constexpr int cell = x / y;
auto a = std::bitset<20>{cell}; // works
Run Code Online (Sandbox Code Playgroud)
您现在可能会问为什么列表初始化不允许缩小转换范围。我无法完全回答这个问题。我的理解是,隐式缩小通常被认为是不可取的,因为它可能会产生意想不到的后果,因此被排除在外。