不同的编译器行为表达式:auto p {make_pointer()};

Different compiler behavior for expression: auto p {make_pointer()};

本文关键字:make pointer auto 编译器 表达式      更新时间:2023-10-16

以下程序的正确行为是什么?

// 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开发人员似乎确实打算将其后端移植。这种情况并没有发生,原因也不清楚。