将const添加到size_t会导致编译失败是标准行为吗?

NoS*_*tAl 6 c++ gcc clang language-lawyer c++11

我最近阅读了很酷的文章: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());
}
Run Code Online (Sandbox Code Playgroud)

不编译,但与const删除编译相同的程序:

#include <iostream>
#include <cassert>
using namespace std;
int main() {
    size_t sz=258;
    string s{sz,'#'};
    assert(2==s.size());
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是这个标准要求或只是编译器决定一个是编译器警告而另一个是编译器错误.

如果它有帮助,这里是gcc 5.1(tnx godbolt)的错误和警告

!!错误:缩小'258ul'从'size_t {aka long unsigned int}'到'char'的转换{}


!!警告:缩小'sz'从'size_t {aka long unsigned int}'转换为'char'的内部{} [-Wnarrowing]

好人铿锵3.6在这两种情况下都给出了错误,但问题仍然存在,是一个合法而糟糕的C++和其他非法C++?

Tar*_*ama 7

std::string 将构造函数声明为:

string::string(std::initializer_list<char>);
string::string(std::size_t, char);
Run Code Online (Sandbox Code Playgroud)

当我们进行列表初始化时,以下规则适用:

(N3337 [dcl.init.list]/3): 列表初始化对象或类型T的引用定义如下:

  • [...]
  • 否则,如果T是类类型,则考虑构造函数.枚举适用的构造函数,并通过重载决策(13.3,13.3.1.7)选择最佳构造函数.如果转换任何参数需要缩小转换(见下文),则程序格式错误.

由于此规则,选择了初始化列表构造函数:

(N3337 [over.match.list]/1): 当非聚合类类型T的对象被列表初始化(8.5.4)时,重载决策分两个阶段选择构造函数:

  • 最初,候选函数是类T的初始化列表构造函数(8.5.4),参数列表由初始化列表作为单个参数组成.
  • [...]

现在,由于初始化列表构造函数是最佳选择,但转换参数需要缩小转换,因此程序生成错误.

但是,我不认为这会使一个编译器正确,一个不正确:

(N3337 [intro.compliance]/8):符合条件的实现可能具有扩展(包括其他库函数),前提是它们不会改变任何格式良好的程序的行为.需要实现来诊断使用根据本国际标准格式不正确的扩展的程序.但是,这样做之后,他们就可以编译和执行这样的程序.

该标准没有警告与错误的概念,因此GCC在发出警告诊断时是一致的,然后继续编译程序.请注意,如果通过,GCC 发出错误-pedantic-errors.