簡體   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