std::variant<>::get() does not compile with Apple LLVM 10.0
Asked Answered
I

2

19

I'm playing with the C++17 std::variant type and tried to compile the cppreference example code for get():

#include <variant>
#include <string>

int main()
{
    std::variant<int, float> v{12}, w;
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // same effect as the previous line

//  std::get<double>(v); // error: no double in [int, float]
//  std::get<3>(v);      // error: valid index values are 0 and 1

    try {
      std::get<float>(w); // w contains int, not float: will throw
    }
    catch (std::bad_variant_access&) {}
}

in XCode 10. My project is set to C++17, but I get compiler errors:

Call to unavailable function 'get': introduced in macOS 10.14

and

'bad_variant_access' is unavailable: introduced in macOS 10.14

which is surprising in 2 ways: it should compile if std::variant is supported and the hint about macOS 10.14 is weird, given that I'm on that version and it has nothing to do with the supported C++ dialect (and the project's deployment target is 10.14).

Is this something I'm doing wrong or a bug in clang?

Intramundane answered 26/9, 2018 at 15:30 Comment(0)
I
5

As it turned out the project was set to macOS 10.14, but not the actual build target, which was still on 10.13. Once I reverted that to inherit the deployment target, the test code started to compile fine.

It's an interesting twist, given that XCode 10 (and hence LLVM 10.0) can be installed and used to build C++17 apps on 10.13.

Intramundane answered 26/9, 2018 at 15:38 Comment(3)
It seems an intentional breakage on the Apple side to encourage the upgrade of Mojave. Official LLVM (which can be installed by Homebrew) has no problems at all.Latoya
I guess that means you cannot use std::variant on 10.13 targets.Intramundane
Yes, if the code is intended to work with the default compiler. As I do not mainly develop for Mac, just on Mac, I am free to use other compilers. It is still a big pity that Apple is being mean and allows a fully normal non-OS-dependent feature to work only on the latest macOS/iOS/… version.Latoya
T
25

All std::variant functionality that might throw std::bad_variant_access is marked as available starting with macOS 10.14 (and corresponding iOS, tvOS and watchOS) in the standard header files. This is because the virtual std::bad_variant_access::what() method is not inline and thus defined in the libc++.dylib (provided by the OS).

If you want to use std::variant in apps running on older OSes, just use std::get_if. In your example:

if (auto* p = std::get_if<int>(&w)) {
  // use *p
} else {
  // error handling
}

You can also check in advance with w.index() and std:: holds_alternative <int>(w).

EDIT: Also see my answer to the similar problem with std::visit (unfortunately with a less handy workaround)

Taxable answered 21/12, 2018 at 15:12 Comment(5)
Good explanation - now we know why this limitation exists (and a workaround)!Intramundane
can we use std::get_if to simulate the behavior of std::get? The former one is quite verbose :(Ponceau
@Ponceau What do you mean by simulate? You can factor this out into your own::get function template. But which exception would that throw?Taxable
@Taxable just throw something like runtime_error is enough for me. but I am a bit worried about the reference vs pointer - I have to dereference the pointer and return it as a reference - is this safe? Is my naive implemention correct or not? -> gist.github.com/fzyzcjy/8633198b2cb03fe8585870d1a554d101Ponceau
Looks good to me, @ch271828n. But in general you would have to provide all four overloads (type/index template argument) x (const/non-const variant argument).Taxable
I
5

As it turned out the project was set to macOS 10.14, but not the actual build target, which was still on 10.13. Once I reverted that to inherit the deployment target, the test code started to compile fine.

It's an interesting twist, given that XCode 10 (and hence LLVM 10.0) can be installed and used to build C++17 apps on 10.13.

Intramundane answered 26/9, 2018 at 15:38 Comment(3)
It seems an intentional breakage on the Apple side to encourage the upgrade of Mojave. Official LLVM (which can be installed by Homebrew) has no problems at all.Latoya
I guess that means you cannot use std::variant on 10.13 targets.Intramundane
Yes, if the code is intended to work with the default compiler. As I do not mainly develop for Mac, just on Mac, I am free to use other compilers. It is still a big pity that Apple is being mean and allows a fully normal non-OS-dependent feature to work only on the latest macOS/iOS/… version.Latoya

© 2022 - 2024 — McMap. All rights reserved.