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
实际上,这个错误似乎是由bad_optional_access
的定义引起的,即使在使用clang时会出现问题。
EDIT2
没有命令行参数,但是-std=c++14
在osx上使用clang执行的测试,只要你不使用optional
成员方法,它编译就好(所以value
是免费的)。
这意味着它使用以下编译和链接:
opt->bar
而不是:
opt.value().bar
答案 0 :(得分:2)
你的代码看起来很好,opt.value()
应该返回对包含值的引用,假设它已经被引用或抛出异常。我们可以看一下older proposals中有一个比后者更多的例子,它包括以下段落:
对脱离对象使用间接运算符是一种未定义的行为。此行为提供最大的运行时性能。除了间接运算符之外,我们提供成员函数值,如果存在或者抛出异常(从logic_error派生),则返回对包含值的引用,否则
如果查看latest proposal,请将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( see it live )。
正如Petesh所说,这可能是您平台上的故意,但确认这是提交错误报告的唯一方法。
另请注意,提案注意到还有reference implementation on github可能是短期选项。
答案 1 :(得分:0)
<强> TL; DR:强>
@ Petesh在评论中的解决方案为我解决了问题(发生在OSX上的源代码中构建的Clang 4.0.0),即在...中添加默认实现(std::experimental::bad_optional_access::~bad_optional_access() _NOEXCEPT = default;
)实验/可选:
(void)0
。
<强>详细信息:强>
根据@ Shafik的回答使用取消引用运算符不能按预期工作,因为当取消引用脱离的可选项时,当前实现提供(void)0
作为值。例如,这为可选项产生0 - 这是不正确的行为。 (我也不认为(dis)参与检查应该作为断言实现,因为断言很可能是在发布版本中编译出来的,这是出乎意料的。)
要修复_LIBCPP_ASSERT
问题,必须使用正确的行为定义_LIBCPP_DEBUG_LEVEL
- 如果要将_LIBCPP_ASSERT
定义为至少1,则会定义((x) ? (void)0 : (_VSTD::fprintf(stderr, "%s\n", m), _VSTD::abort()))
作为_LIBCPP_DEBUG_LEVEL
,它应该产生预期的行为。
但问题是,根据libc++ docs,document.getElementById("input here")
是一项正在进行的工作,并且定义它将产生相当讨厌的编译错误&#34;。好吧,我试过了,他们没有说谎。 :(