5

With this trivial example, I get a compilation error:

#include <unordered_map>

int main() {
    std::unordered_map<int, int> a, b;
    a.merge(b);
}

Error:

$ clang++ -std=c++17 merge.cpp
merge.cpp:5:4: error: no member named 'merge' in 'std::__1::unordered_map<int, int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<const int, int> > >'
        a.merge(b);
        ~ ^
1 error generated.

Versions:

$ clang++ --version
clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-apple-darwin17.5.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin

According to cppreference, this should be legal since C++17. GCC 7 is happy to compile it.

mrks
  • 8,033
  • 1
  • 33
  • 62

1 Answers1

2

I had same issue. I was outraged, why I can't compile application which use unordered_map::merge() using macOS 10.14.6

unordered_map::merge() was added in c++17 with proposal P0083R3 "Splicing Maps and Sets (Revision 5)", see github blame.

Documentation presents common compilers' support for new C++ features. Find row "Splicing Maps and Sets" and check you compiler version.

"Splicing Maps and Sets" compilers' support:

+-----------------------+---------------------+------+
| Compiler              | Version             | Link |
+-----------------------+---------------------+------+
| GCC libstdc++         |                 7.1 | [1]  |
| Clang libc++          |                 8.0 | [2]  |
| MSVC Standard Library | 19.12 (VS 2017 15.5)| [3]  |
| Apple Clang           |                   - | [4]  |
+-----------------------+---------------------+------+
  1. https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
  2. https://libcxx.llvm.org/Cxx1zStatus.html#cxx1z-status
  3. https://learn.microsoft.com/cpp/overview/visual-cpp-language-conformance?view=vs-2019
  4. Apple LLVM have special implementation of clang compiler, see description below

if you request a clang version, you get something like this:

➜ ~ clang++ --version

Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Apple's clang version number has nothing to with the official's one. Some users try to map apple's and official clang versions here. I think, it's not always possible.

Also I couldn't find exhaustive table of c++ standard support status for different Apple Clang versions, unlike another compilers (share it in comments if you have). All we have is official xcode release notes.

But mac OS users can still take advantage of all the new features of c++17. You should only... install original llvm. Detailed guide read in article "Installing LLVM/Clang on OSX" by Phillip Johnston.

Installing llvm using brew is much safer:

llvm is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble.

Install llvm:

// optional "--with-toolchain" from article is deprecated
brew install llvm

Check status of llvm

➜ ~ brew info llvm
llvm: stable 8.0.1 (bottled), HEAD [keg-only]
Next-gen compiler infrastructure
https://llvm.org/
/usr/local/Cellar/llvm/8.0.1 (6,807 files, 3.3GB)
  Poured from bottle on 2019-09-14 at 14:19:29
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/llvm.rb
==> Dependencies
Build: cmake ✔
Required: libffi ✔, swig ✔
==> Requirements
Build: xcode ✔
==> Options
--HEAD
    Install HEAD version
==> Caveats
To use the bundled libc++ please add the following LDFLAGS:
  LDFLAGS="-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib"

llvm is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have llvm first in your PATH run:
  echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc

For compilers to find llvm you may need to set:
  export LDFLAGS="-L/usr/local/opt/llvm/lib"
  export CPPFLAGS="-I/usr/local/opt/llvm/include"

Check clang version:

➜ ~ /usr/local/Cellar/llvm/8.0.1/bin/clang++ --version
clang version 8.0.1 (tags/RELEASE_801/final)
Target: x86_64-apple-darwin18.7.0
Thread model: posix

Configure project

Now you can define compiler, I use CMake and add lines in CMakeLists.txt:

set(CMAKE_C_COMPILER "/usr/local/Cellar/llvm/8.0.1/bin/clang")
set(CMAKE_CXX_COMPILER "/usr/local/Cellar/llvm/8.0.1/bin/clang++")
set(CMAKE_CXX_STANDARD 17)

or pass cmake command's options:

➜ ~ cmake \
  -D CMAKE_C_COMPILER="/usr/local/Cellar/llvm/8.0.1/bin/clang" \
  -D CMAKE_CXX_COMPILER "/usr/local/Cellar/llvm/8.0.1/bin/clang++" \
  /path/to/CMakeLists.txt

or define env variables:

➜ ~ export CC=/usr/local/Cellar/llvm/8.0.1/bin/clang
➜ ~ export CXX=/usr/local/Cellar/llvm/8.0.1/bin/clang++
➜ ~ cmake /path/to/CMakeLists.txt
user2084795
  • 704
  • 1
  • 7
  • 20