表达式的不同编译器行为: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
此行为受提案和 Evolution 工作组问题的约束。关于将其视为 C++14 缺陷还是 C++1z 提议存在一些歧义。如果证明是 C++14 缺陷,那么 gcc 的行为对于 C++14 是正确的。另一方面,如果这真的是一个 C++1z 提议,那么 clang 和 icpc 就会表现出正确的行为。
详情
N3681 似乎涵盖了这种情况,它说:
Auto and braced initializers cause a teachability problem; we want to
teach people to use uniform initialization, but we need to
specifically tell programmers to avoid braces with auto. In C++14, we
now have more cases where auto and braces are problematic; return type
deduction for functions partially avoids the problem, since returning
a braced-list won't work as it's not an expression. However, returning
an auto variable initialized from a braced initializer still returns
an initializer_list, inviting undefined behaviour. Lambda init
captures have the same problem. This paper proposes to change a
brace-initialized auto to not deduce to an initializer list, and to
ban brace-initialized auto for cases where the braced-initializer has
more than one element.
并提供了以下示例:
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: direct list initialization of a variable with a deduced type
will change meaning in a future version of Clang; insert an '=' to
avoid a change in behavior [-Wfuture-compat]
来自 EWG issue 161 that N3922 为此被采用。
正如 Praetorian 指出的那样,提案建议这是一个 C++14 缺陷:
Direction from EWG is that we consider this a defect in C++14.
但是 clang 的 C++1z implementation status notes 这是一个未实现的 C++1z 提案。
因此,如果这是一个 C++14 缺陷,那将使 gcc 正确,但我不清楚这到底是一个缺陷还是一个提案。
T.C。在 that it seems like the clang developers 中指出确实打算向后移植这个。它并没有发生,也不清楚为什么。
以下程序的正确行为是什么?
// 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
此行为受提案和 Evolution 工作组问题的约束。关于将其视为 C++14 缺陷还是 C++1z 提议存在一些歧义。如果证明是 C++14 缺陷,那么 gcc 的行为对于 C++14 是正确的。另一方面,如果这真的是一个 C++1z 提议,那么 clang 和 icpc 就会表现出正确的行为。
详情
N3681 似乎涵盖了这种情况,它说:
Auto and braced initializers cause a teachability problem; we want to teach people to use uniform initialization, but we need to specifically tell programmers to avoid braces with auto. In C++14, we now have more cases where auto and braces are problematic; return type deduction for functions partially avoids the problem, since returning a braced-list won't work as it's not an expression. However, returning an auto variable initialized from a braced initializer still returns an initializer_list, inviting undefined behaviour. Lambda init captures have the same problem. This paper proposes to change a brace-initialized auto to not deduce to an initializer list, and to ban brace-initialized auto for cases where the braced-initializer has more than one element.
并提供了以下示例:
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: direct list initialization of a variable with a deduced type will change meaning in a future version of Clang; insert an '=' to avoid a change in behavior [-Wfuture-compat]
来自 EWG issue 161 that N3922 为此被采用。
正如 Praetorian 指出的那样,提案建议这是一个 C++14 缺陷:
Direction from EWG is that we consider this a defect in C++14.
但是 clang 的 C++1z implementation status notes 这是一个未实现的 C++1z 提案。
因此,如果这是一个 C++14 缺陷,那将使 gcc 正确,但我不清楚这到底是一个缺陷还是一个提案。
T.C。在