https://akrzemi1.wordpress.com/2015/08/20/can-you-see-the-bug/
在ideone上使用简化版本我得到了令人惊讶的行为:
#include <iostream> #include <cassert> using namespace std; int main() { const size_t sz=258; string s{sz,'#'}; assert(2==s.size()); }
不编译,但是
与const删除编译相同的程序:
#include <iostream> #include <cassert> using namespace std; int main() { size_t sz=258; string s{sz,'#'}; assert(2==s.size()); }
所以我的问题是这个标准要求或只是编译器决定一个是编译器警告而另一个是编译器错误.
如果它有帮助,这里是gcc 5.1(tnx godbolt)的错误和警告
!!error: narrowing conversion of ‘258ul’ from ‘size_t {aka long
unsigned int}’ to ‘char’ inside { }
!!warning: narrowing conversion of ‘sz’ from ‘size_t {aka long
unsigned int}’ to ‘char’ inside { } [-Wnarrowing]
好人铿锵3.6在这两种情况下都给出了错误,但问题仍然存在,是一个合法和坏C和其他非法C?
解决方法
string::string(std::initializer_list<char>); string::string(std::size_t,char);
当我们进行列表初始化时,以下规则适用:
(N3337 [dcl.init.list]/3):
List-initialization of an object or reference of type T is defined as follows:
- […]
- Otherwise,if T is a class type,constructors are considered. The applicable constructors are enumerated
and the best one is chosen through overload resolution (13.3,13.3.1.7). If a narrowing conversion (see
below) is required to convert any of the arguments,the program is ill-formed.
由于此规则,选择了初始化列表构造函数:
(N3337 [over.match.list]/1):
When objects of non-aggregate class type T are list-initialized (8.5.4),overload resolution selects the constructor in two phases:
- Initially,the candidate functions are the initializer-list constructors (8.5.4) of the class T and the
argument list consists of the initializer list as a single argument.- […]
现在,由于初始化列表构造函数是最佳选择,但转换参数需要缩小转换,因此程序生成错误.
但是,我不认为这会使一个编译器正确,一个不正确:
(N3337 [intro.compliance]/8):
A conforming implementation may have extensions (including additional library functions),provided they do
not alter the behavior of any well-formed program. Implementations are required to diagnose programs that
use such extensions that are ill-formed according to this International Standard. Having done so,however,
they can compile and execute such programs.
该标准没有警告与错误的概念,因此GCC在发出警告诊断时是一致的,然后继续编译程序.请注意,如果传递-pedantic-errors,GCC将发出错误.