Clang与std :: experimental :: optional无法正常工作

时间:2015-12-09 16:02:21

标签: c++ macos clang c++14 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

实际上,这个错误似乎是由bad_optional_access的定义引起的,即使在使用clang时会出现问题。

EDIT2

没有命令行参数,但是-std=c++14 在osx上使用clang执行的测试,只要你不使用optional成员方法,它编译就好(所以value是免费的)。 这意味着它使用以下编译和链接:

opt->bar

而不是:

opt.value().bar

2 个答案:

答案 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++ docsdocument.getElementById("input here")是一项正在进行的工作,并且定义它将产生相当讨厌的编译错误&#34;。好吧,我试过了,他们没有说谎。 :(