c++ - Xcode 10 调用不可用的函数 std::visit

标签 c++ ios xcode c++17

使用 Xcode 10 GM 编译以下程序时:

#include <iostream>
#include <string>
#include <variant>

void hello(int) {
    std::cout << "hello, int" << std::endl;
}

void hello(std::string const & msg) {
    std::cout << "hello, " << msg << std::endl;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::variant< int, std::string > var;

    std::visit
    (
        []( auto parameter )
        {
            hello( parameter );
        },
        var
     );

    return 0;
}

我收到以下错误:

main.cpp:27:5: Call to unavailable function 'visit': introduced in macOS 10.14

但是,如果我将最小部署目标更改为 macOS 10.14,即使我运行的是 macOS 10.13,代码也可以正常编译并且可以正常工作。

由于 std::visit 是函数模板,并且不应该依赖于操作系统版本(我通过在低于实际支持的 mac 版本上运行代码证明了这一点),这应该被视为错误并报告给 Apple 还是这是预期的行为?

在为 iOS 编译时也会发生同样的情况(至少需要 iOS 12)。

最佳答案

所有可能抛出 std::bad_variant_accessstd::variant 功能在标准中从 macOS 10.14(以及相应的 iOS、tvOS 和 watchOS)开始标记为可用头文件。这是因为虚拟 std::bad_variant_access::what() 方法不是 inline 并因此在 libc++.dylib 中定义(由操作系统)。

有几种解决方法(技术上都是未定义的行为),按我的个人喜好排序:

1) 参与实现

std::visit 仅在变体参数之一是 valueless_by_exception 时抛出。查看实现为您提供了使用以下解决方法的线索(假设 vs 是变体的参数包):

if (... && !vs.valueless_by_exception() ) {
  std::__variant_detail::__visitation::__variant::__visit_value(visitor, vs...);
} else {
  // error handling
}

缺点:可能会与 future 的 libc++ 版本中断。丑陋的界面。

专业人士:编译器可能会在它崩溃时对你大喊大叫,并且可以轻松调整解决方法。您可以针对丑陋的界面编写一个包装器。

2) 抑制可用性编译器错误...

_LIBCPP_DISABLE_AVAILABILITY 添加到项目设置 Preprocessor Macros (GCC_PREPROCESSOR_DEFINITIONS)

缺点:这也会抑制其他可用性保护(shared_mutexbad_optional_access 等)。

2a) ... 并使用它

事实证明它已经在 High Sierra 中工作,而不仅仅是 Mojave(我已经测试到 10.13.0)。

在 10.12.6 及以下版本中,您会收到运行时错误:

dyld: Symbol not found: __ZTISt18bad_variant_access
  Referenced from: [...]/VariantAccess
  Expected in: /usr/lib/libc++.1.dylib
 in [...]/VariantAccess
Abort trap: 6

第一行解构为 _typeinfo for std::bad_variant_access。这意味着动态链接器(dyld)找不到指向引言中提到的what()方法的vtable。

缺点:仅适用于某些操作系统版本,如果它不起作用,您只有在启动时才知道。

专业版: 保持原始界面。

2b) ...并提供您自己的异常实现

在您的项目源文件之一中添加以下行:

// Strongly undefined behaviour (violates one definition rule)
const char* std::bad_variant_access::what() const noexcept {
    return "bad_variant_access";
}

我已经针对 10.10.0、10.12.6、10.13.0、10.14.1 上的独立二进制文件对此进行了测试,即使导致 std::bad_variant_access 为抛出,由 std::exception const& ex 捕获,并调用虚拟 ex.what()

缺点:我的假设是,当使用 RTTI 或跨二进制边界(例如不同的共享对象库)进行异常处理时,这个技巧会失效。但这只是一个假设,这就是我把这个解决方法放在最后的原因:我不知道它什么时候会破裂以及会出现什么症状。

专业版: 保持原始界面。可能适用于所有操作系统版本。

关于c++ - Xcode 10 调用不可用的函数 std::visit,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52310835/

相关文章:

Xcode无法使用所选目标运行

c++ - new() 和 delete() 作为 C++ 中的运算符?

iphone - 应用更新后处理丢失的 NSUserDefault 键

ios - iOS中的自定义控件开发

ios - iPhone x 上的 Y 位置关闭

c++ - 如何抑制 Xcode 发出 -stdlib 标志?

c++ - OpenCV 错误信息(匹配模板)

c++ - 我如何确保槽在特定线程的上下文中执行?

c++ - 将 boost::posix_time::duration 设置为 pos_infinite?

iphone - 从搜索结果 UITableView 添加 segue