[英]Clang does not work properly with std::experimental::optional
似乎clang与std::experimental::optional
不能正常工作。
请考虑以下示例:
#include <experimental/optional>
#include <iostream>
struct Foo { int bar; };
int main() {
Foo foo;
std::experimental::optional<Foo> opt = foo;
opt.value().bar = 42;
std::cout << opt.value().bar << std::endl;
}
它与g ++版本5.3.1编译良好,但它既没有clang版本7.0.0也没有clang版本7.0.2。
返回的错误是:
Undefined symbols for architecture x86_64:
"std::experimental::bad_optional_access::~bad_optional_access()", referenced from:
_main in main-11b2dd.o
"typeinfo for std::experimental::bad_optional_access", referenced from:
_main in main-11b2dd.o
"vtable for std::experimental::bad_optional_access", referenced from:
std::experimental::bad_optional_access::bad_optional_access() in main-11b2dd.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我没有设法在clang的bug报告中找到任何问题。
谁表现得很好? 我猜g ++工作得很好,而clang似乎被窃听了。 我错了吗?
EDIT1
实际上,这个bug似乎是由于bad_optional_access
的定义,即使在使用clang时问题发生了。
EDIT2
没有命令行参数,但是-std=c++14
。
在osx上使用clang进行测试,只要你不使用value
成员方法,它就可以很好optional
编译(所以optional
是免费的)。
这意味着它使用以下方式编译和链接:
opt->bar
代替:
opt.value().bar
您的代码看起来非常好, opt.value()
应该返回对包含值的引用,假设它已被使用或抛出异常。 我们可以看一个较旧的提案 ,其中包含比后者更多的例子,它包括以下段落:
对脱离对象使用间接运算符是一种未定义的行为。 此行为提供最大的运行时性能。 除了间接运算符之外, 我们还提供成员函数值,该值返回对包含的值的引用(如果存在)或抛出异常(从logic_error派生),否则
如果查看最新的提案,它将value()
描述为:
constexpr T const& optional<T>::value() const; T& optional<T>::value();
返回:
*val
,如果bool(*this)
。抛出:
bad_optional_access
if!*this
。备注:
第一个函数应该是
constexpr
函数。
并提供了value
的示例实现:
constexpr T const& value()
{
return *this ? storage_.value_ : (throw bad_optional_access(""), storage_.value_);
}
在你的情况下, opt
是参与的,如果它不是它应该只是抛出,我们不会调用未定义的行为。
注意,这会编译Wandbox上最后几个版本的clang( 请参见实时 )。
因此,Petesh建议这可能是您的平台上的故意,但确认这将是提交错误报告的唯一方法。
TL; DR:
@ Petesh在评论中的解决方案解决了我的问题(发生在OSX上的源代码中构建的Clang 4.0.0),即在... / experimental / optional中添加默认实现( = default
): std::experimental::bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
。
细节:
根据@ Shafik的回答使用解引用运算符不能按预期工作,因为当取消引用脱离的可选项时,当前实现提供(void)0
作为值。 例如,这为可选项产生0 - 这是不正确的行为。 (我也不认为(dis)参与检查应该作为断言实现,因为断言很可能是在发布版本中编译出来的,这是意料之外的。)
以固定(void)0
问题, _LIBCPP_ASSERT
必须用正确的行为被定义-如果_LIBCPP_DEBUG_LEVEL
被定义为至少1,则_LIBCPP_ASSERT
将被定义为((x) ? (void)0 : (_VSTD::fprintf(stderr, "%s\\n", m), _VSTD::abort()))
,它应该产生预期的行为。
但问题是,根据libc ++文档 , _LIBCPP_DEBUG_LEVEL
是一项正在进行的工作,定义它将产生“相当讨厌的编译错误”。 好吧,我试过了,他们没有说谎。 :(
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.