【发布时间】:2017-10-18 21:38:12
【问题描述】:
程序:
#include <stdio.h>
struct bar_t {
int value;
template<typename T>
bar_t (const T& t) : value { t } {}
// edit: You can uncomment these if your compiler supports
// guaranteed copy elision (c++17). Either way, it
// doesn't affect the output.
// bar_t () = delete;
// bar_t (bar_t&&) = delete;
// bar_t (const bar_t&) = delete;
// bar_t& operator = (bar_t&&) = delete;
// bar_t& operator = (const bar_t&) = delete;
};
struct foo_t {
operator int () const { return 1; }
operator bar_t () const { return 2; }
};
int main ()
{
foo_t foo {};
bar_t a { foo };
bar_t b = static_cast<bar_t>(foo);
printf("%d,%d\n", a.value, b.value);
}
gcc 7/8 的输出:
2,2
clang 4/5 的输出(也适用于 gcc 6.3)
1,1
在创建bar_t的实例时似乎发生了以下情况:
对于gcc,它是calls foo_t::operator bar_t,然后是constructs bar_t with T = int。
对于clang,它是constructs bar_t with T = foo_t,然后是calls foo_t::operator int
这里哪个编译器是正确的? (或者如果这是某种形式的未定义行为,它们可能都是正确的)
【问题讨论】:
-
对我来说,似乎因为
bar_t仍将具有bar_t(const bar_t&)形式的默认构造函数,并且由于常规函数击败模板函数,因为匹配所有事物都相同,因此正确的转换顺序在这两种情况都是 gcc 7,8 之后的情况。我看不出clang 4/5是正确的任何可能的方式。充其量是模棱两可的。 -
@isanae 从 C++17 开始,在强制复制省略的情况下不需要构造函数。
-
呃,如果你不能提前说construct的效果是什么,那就不要使用它。三个编译器都对此意见不一,逃命吧。 ;-)
-
MSVC 没有实现 C++17 保证省略。 Clang 是正确的。
-
@T.C.它确实在 VS2017 的最新 (3) 更新中实现了它:blogs.msdn.microsoft.com/vcblog/2017/05/10/…
标签: c++ gcc clang language-lawyer compiler-bug