在 LLVM/Clang 下编译时,命名空间 'std' 中没有名为 'unique_ptr' 的类型

No type named 'unique_ptr' in namespace 'std' when compiling under LLVM/Clang

我在 Apple 平台上尝试使用 unique_ptr 时遇到编译错误 -std=c++11:

$ make
c++ -std=c++11 -DNDEBUG -g2 -O3 -fPIC -march=native -Wall -Wextra -pipe -c 3way.cpp
In file included ...
./smartptr.h:23:27: error: no type named 'unique_ptr' in namespace 'std'
    using auto_ptr = std::unique_ptr<T>;
                     ~~~~~^
./smartptr.h:23:37: error: expected ';' after alias declaration
    using auto_ptr = std::unique_ptr<T>;

根据 Marshall Clow 的说法,我认为他是 C++ Standard Library with Clang and Apple 方面的专家:

Technical Report #1 (TR1) was a set of library additions to the C++03 standard. Representing the fact that they were not part of the "official" standard, they were placed in the namespace std::tr1.

In c++11, they are officially part of the standard, and live in the namespace std, just like vector and string. The include files no longer live in the "tr1" folder, either.

外卖:

现在,这是我在 smartptr.h 中的内容:

#include <memory>

// Manage auto_ptr warnings and deprecation in C++11
// Microsoft added template aliases to VS2015
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900)
  template<typename T>
    using auto_ptr = std::unique_ptr<T>;
#else
  using std::auto_ptr;
#endif // C++11

我认为最后要检查的是 __APPLE__ 定义,这里是:

$ c++ -x c++ -dM -E - < /dev/null | grep -i apple
#define __APPLE_CC__ 6000
#define __APPLE__ 1
#define __VERSION__ "4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)"
#define __apple_build_version__ 5030040

为什么我在使用 -std=c++11 时收到 error: no type named 'unique_ptr' in namespace 'std'


我认为这是四个测试用例。它尝试从以下项的叉积中练习四种配置:{C++03,C++11} x {libc++,libstdc++}。

这里是试车手。请务必在 OS X 上对其进行测试,以便在 2015 年获得 TR1 命名空间的全部效果。

$ cat test-clapple.cxx

// c++ -c test-clapple.cxx
// c++ -stdlib=libc++ -c test-clapple.cxx
// c++ -std=c++11 -c test-clapple.cxx
// c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx

#include <memory>

// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900)
  template<typename T>
    using auto_ptr = std::unique_ptr<T>;
#else
    using std::auto_ptr;
#endif // C++11

int main(int argc, char* argv[])
{
    return argc;
}

And the CFE Devs specifically told me to use that code;

不,他们没有。如果你想使用 shared_ptr,他们告诉你做类似的事情,因为对于 C++03 <tr1/memory> 定义 std::tr1::shared_ptr 而对于 C++11 <memory> 定义 std::shared_ptr.

但是您没有使用 shared_ptr。如果你想使用 auto_ptr 那么它只是 std::auto_ptr,无处不在,它总是在 <memory>.

中定义

我认为你误解了 Marshall 的评论,你把事情复杂化了。你引用的('In c++11, they are officially part of the standard, and live in the namespace std, just like vector and string. The include files no longer live in the "tr1" folder, either.')不是Apple-specific或Clang-specific,它适用于所有编译器。但是由于 auto_ptr 从来都不是 TR1 的一部分,也从来没有在 <tr1/memory> 中,因此 TR1 的内容现在位于命名空间 std 中是无关紧要的,因为您尝试使用的内容从未包含在 TR1 中.

你根本不应该在这里使用 TR1

# include <memory>

// Manage auto_ptr warnings and deprecation in C++11
#if (__cplusplus >= 201103L)
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif // C++11

这对于现代编译器应该是正确的,但不适用于 XCode 附带的愚蠢配置,它是支持 C++11 和 GCC 4.2 的 libstdc++ 的现代版本的 Clang将近十年了,不支持 unique_ptr.

为了处理默认的 OS X 工具链,这个有效:

#include <memory>

#if __cplusplus >= 201103L
# ifdef __clang__
#  if __has_include(<forward_list>)
// either using libc++ or a libstdc++ that's new enough to have unique_ptr
#   define HAVE_UNIQUE_PTR 1
#  endif
# else // not clang, assume unique_ptr available
#  define HAVE_UNIQUE_PTR 1
# endif
#endif

#ifdef HAVE_UNIQUE_PTR
template<typename T> using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif

这通过使用 <forward_list> 的存在作为标准库 clang 正在使用的指标是否支持 std::unique_ptr.

来工作

如果clang使用libc++作为标准库那么所有版本都支持unique_ptr并且还提供<forward_list>,所以测试通过

如果 clang 使用 libstdc++,那么是否支持 unique_ptr 取决于 libstdc++ 版本。 unique_ptr 已添加到 GCC 4.3 中的 libstdc++,这是添加 <forward_list> 的同一版本,因此如果 header 可用,那么 unique_ptr 也将可用。如果您将 clang 与 Apple 工具链(来自 GCC 4.2)附带的古老 libstdc++ 一起使用,则不支持 unique_ptr,但也不支持 <forward_list>,因此测试失败,您使用 auto_ptr 相反。

这应该适用于在野外发现的任何 GCC/libstdc++、Clang/libc++ 或 Clang/libstdc++ 组合。我不知道 VC++/Dinkumware 和 Clang/Dinkumware 需要什么,根据您的回答,您可能只需将第一个条件更改为:

#if __cplusplus >= 201103L || _MSC_VER >= 1600