不同的编译器行为表达式:auto p {make_pointer()};
Different compiler behavior for expression: auto p {make_pointer()};
以下程序的正确行为是什么?
// example.cpp
#include <iostream>
#include <memory>
struct Foo {
void Bar() const {
std::cout << "Foo::Bar()" << std::endl;
}
};
std::shared_ptr<Foo> MakeFoo() {
return std::make_shared<Foo>();
}
int main() {
auto p { MakeFoo() };
p->Bar();
}
当我在Linux RHEL 6.6工作站上编译它时,我得到了以下结果:
$ g++ -v
gcc version 5.1.0 (GCC)
$ g++ example.cpp -std=c++14 -Wall -Wextra -pedantic
$ ./a.out
Foo::Bar()
,
$ clang++ -v
clang version 3.6.0 (trunk 217965)
$ clang++ example.cpp -std=c++14 -Wall -Wextra -pedantic
example.cpp:16:4: error: member reference type 'std::initializer_list<std::shared_ptr<Foo> >' is not a pointer; maybe you meant to use '.'?
p->Bar();
~^~
example.cpp:16:6: error: no member named 'Bar' in 'std::initializer_list<std::shared_ptr<Foo> >'
p->Bar();
~ ^
2 errors generated.
和
$ icpc -v
icpc version 15.0.3 (gcc version 5.1.0 compatibility)
$ icpc example.cpp -std=c++14 -Wall -Wextra -pedantic
example.cpp(16): error: expression must have pointer type
p->Bar();
^
compilation aborted for example.cpp (code 2)
Tl;DR
此行为受制于提案和演进工作组的问题。至于这是c++ 14的缺陷还是c++ 1z的建议,存在一些歧义。如果这是c++ 14的缺陷,那么gcc的行为对于c++ 14是正确的。另一方面,如果这确实是一个c++ 1z提案,那么clang和icpc表现出正确的行为。
细节看起来这个案例是由N3681覆盖的,上面写着:
Auto和带括号的初始化式会导致可教性问题;我们想要教人们使用统一初始化,但我们需要这样做明确地告诉程序员避免使用大括号auto。在c++ 14中,我们现在有更多auto和大括号有问题的情况;返回类型函数的演绎部分地避免了这个问题,因为返回大括号列表不起作用,因为它不是表达式。然而,返回从带括号的初始化项初始化的自动变量仍然返回initializer_list,邀请未定义的行为。λinit捕获也有同样的问题。本文建议改变a大括号初始化auto为不推导到初始化列表,并为禁止在括号初始化器有多于一个元素
,并提供以下示例:
auto x = foo(); // copy-initialization auto x{foo}; // direct-initialization, initializes an initializer_list int x = foo(); // copy-initialization int x{foo}; // direct-initialization
所以我认为clang目前是正确的,最新版本的clang提供了这个警告:
warning:直接初始化具有推导类型的变量的列表会在Clang的未来版本中改变意思;插入一个'='到避免改变行为[-Wfuture-compat]
来自EWG第161期,N3922被采用。
正如Praetorian所指出的,这是c++ 14的一个缺陷:
EWG的方向是我们认为这是c++ 14中的一个缺陷。
但是clang的c++ 1z实现状态指出这是一个没有实现的c++ 1z提案。
因此,如果这是c++ 14的缺陷,这将使gcc正确,但我不清楚这是否真的是一个缺陷或建议。
教学楼。在这里的评论中指出,clang开发人员似乎确实打算将其后端移植。这种情况并没有发生,原因也不清楚。
- C++ - "!pointer"和"pointer == nullptr"的区别?
- VS Code "command":"make"与终端窗口中的命令行"make"不同
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- make 命令如何避免重新编译未更改的源文件?
- MAKE:找不到包含的用户定义的头文件?
- 'make check' GLIBC 运行时的链接问题
- "No-Const Pointer to Const "调用功能
- "owned pointer"和 std::shared_ptr 的"stored pointer"有什么区别?
- 删除分配的 (?) 指针时"Pointer being freed was not allocated"
- Qt5 [make -snap] 无法正确编译:进程"/usr/bin/snap"代码 1 退出
- mingw32-make 使用"MinGW Makefiles"生成器跟踪 CMAKE 无法将可执行文件链接到对象库
- make 命令创建 .file,但不创建应用程序文件
- 如何摆脱导入的 make 项目中的 Eclipse 索引器"Type std::... could not be resolved"错误
- C++ 中的构造函数、继承、堆栈、堆、this-pointer 和段错误
- Qt Creator 在执行步骤 "make" 时出现编译错误,-fno-stack-limit
- "Called Object Type is Not a Function or Pointer" 与 typedef 和类
- 如何使用MySQL Connector and Make设置C++项目
- 使用 make 将对象文件放在特定目录中
- 马洛克会在 C++17 年返回"invalid pointer value"吗?
- 我是 C++ 的新手,我试图调用 make 一个以 2 个类作为其参数的类构造函数