[英]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.