繁体   English   中英

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

[英]Clang does not work properly with std::experimental::optional

似乎clangstd::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建议这可能是您的平台上的故意,但确认这将是提交错误报告的唯一方法。

另请注意,提案注意到github上也有一个参考实现 ,可能是一个短期选项。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM