【发布时间】:2019-04-05 16:02:05
【问题描述】:
Clang 6、clang 7 和 gcc 7.1、7.2 和 7.3 都同意以下是有效的 C++17 代码,但在 C++14 和 C++11 下是模棱两可的。 MSVC 2015 和 2017 也接受它。但是,即使在 c++17 模式下,gcc-8.1 和 8.2 也会拒绝它:
struct Foo
{
explicit Foo(int ptr);
};
template<class T>
struct Bar
{
operator T() const;
template<typename T2>
explicit operator T2() const;
};
Foo foo(Bar<char> x)
{
return (Foo)x;
}
接受它的编译器选择模板化显式转换函数Bar::operator T2()。
拒绝它的编译器同意以下之间存在歧义:
- 显式转换函数 Bar::operator int()
- 首先使用从
Bar<char>到char的隐式用户定义转换,然后从char到int的隐式内置转换,然后是显式构造函数Foo(int)。
那么,哪个编译器是正确的? C++14和C++17的标准有什么相关区别?
附录:实际错误信息
这是gcc-8.2 -std=c++17 的错误。 gcc-7.2 -std=c++14 打印同样的错误:
<source>: In function 'Foo foo(Bar<char>)':
<source>:17:17: error: call of overloaded 'Foo(Bar<char>&)' is ambiguous
return (Foo)x;
^
<source>:3:14: note: candidate: 'Foo::Foo(int)'
explicit Foo(int ptr);
^~~
<source>:1:8: note: candidate: 'constexpr Foo::Foo(const Foo&)'
struct Foo
^~~
<source>:1:8: note: candidate: 'constexpr Foo::Foo(Foo&&)'
这是来自clang-7 -std=c++14 的错误(clang-7 -std=c++17 接受代码):
<source>:17:12: error: ambiguous conversion for C-style cast from 'Bar<char>' to 'Foo'
return (Foo)x;
^~~~~~
<source>:1:8: note: candidate constructor (the implicit move constructor)
struct Foo
^
<source>:1:8: note: candidate constructor (the implicit copy constructor)
<source>:3:14: note: candidate constructor
explicit Foo(int ptr);
^
1 error generated.
【问题讨论】:
-
clang++ 6.0.1 给了我一个链接器错误。命令:
clang++ -fsanitize=undefined -std=c++17 -Wall -Wextra -Wshadow -Weffc++ -pedantic -pedantic-errors -Wc++14-compat -Wc++17-compat -o explicit explicit.cpp输出:/tmp/explicit-71c2bd.o: In functionfoo(Bar)':explicit.cpp:(.text+0x15): undefined reference to Bar<char>::operator Foo<Foo>() const' clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation) -
@ted 自然。我已将示例简化为不包含函数的任何实现,因为这在这里无关紧要。用 -c 编译,如果你愿意的话,用 -S 来查看汇编输出。
-
如果您使用正确的 C++ 强制转换会发生什么?
-
static_cast或函数样式转换显示相同的行为,声明一个新变量并对其进行初始化:Foo y(x);Foo z{x};
标签: c++ c++14 language-lawyer c++17 implicit-conversion