请考虑以下代码:
#include <iostream>
int main()
{
int i{10.1}; // narrowing, should not compile
std::cout << i << std::endl;
}根据C++11标准,它不应该编译(禁止在大括号初始化中缩小范围)。
现在,使用g++4.9.2 -std=c++11编译只会发出警告
warning: narrowing conversion of '1.01e+1' from 'double' to 'int' inside { } [-Wnarrowing]移除-std=c++11标志将导致关于大括号init的警告,但不会导致任何缩窄:
warning: extended initializer lists only available with -std=c++11 or -std=gnu++11另一方面,g++5 不编译,前提是使用g++5 -std=c++11进行编译。但是,如果省略了-std=c++11,那么即使是g++5也会愉快地编译它,只给出一个与大括号init相关的警告,而不是对缩窄的警告:
warning: extended initializer lists only available with -std=c++11 or -std=gnu++11上面的行为似乎是错误的,g++4.9不应该编译代码,如果您忘记指定-std=c++11,那么g++5编译它就更奇怪了。这是一个已知的问题吗?
发布于 2015-02-11 23:25:02
{}内部的缩窄转换只是C++11模式中的错误的原因很简单:它不是C++03中的错误。现在,T var{value};是新的C++11语法,但是T var = {value};已经是有效的C++03语法,并且确实允许收缩转换。
int i = { 10.1 }; // valid C++03, invalid C++11这使得GCC开发人员更容易在T var{value};和T var={value};初始化中同样处理缩小转换。这很有用,因为它避免了编译器中警告的两个单独的代码路径。
这使得GCC开发人员更容易接受T var{value};模式下的C++03语法,只需对其进行警告。其他几个C++11语法扩展也在C++03模式下启用。这很有用,因为GCC在标准库的实现中使用了几个C++11语法扩展(在这里,有关它的警告被禁止)。
int i{10.1};不是GCC 4.9在C++11模式下的一个错误,而是GCC 5中的一个错误,原因是没有将它作为一个错误来处理,导致了有效代码被拒绝。C++标准要求将其视为SFINAE上下文中的一个错误,下面是一个有效的C++11程序,由于GCC 4.9的原因,程序运行不正确:
#include <stdio.h>
template <typename T> void f(double) { puts("ok"); }
template <typename T, typename = decltype(T{10.1})> void f(int) { puts("error"); }
int main() { f<int>(1); }这个应该印上"ok“。第二个过载应该被丢弃。
使用GCC 4.9,它打印“错误”,因为第二个重载不会被丢弃,而且int比double更匹配。
发布于 2015-02-11 23:17:37
引用1.4 [intro.compliance]
符合规范的实现可能有扩展(包括附加的库函数),只要它们不改变任何格式良好的程序的行为。根据本国际标准,实现需要诊断使用此类扩展的程序,这些扩展的格式不正确。但是,这样做之后,他们就可以编译和执行这样的程序。
初始化示例的适用部分是8.5.4 [dcl.init.list]。特别地,
否则,如果初始化程序列表有一个类型为E的元素,并且T不是引用类型,或者其引用类型与E相关,则从该元素初始化对象或引用;如果需要缩小转换(参见下文)才能将元素转换为T,则程序不正确。
附例
int x1 {2}; // OK
int x2 {2.0}; // error: narrowing由于诊断的确切性质是指定的实现,因此所观察到的两组行为都符合标准。
https://stackoverflow.com/questions/28466069
复制相似问题