Using unique_ptr in both C++03 and C++11 mode?

My apologies for asking a user question on CFE Devs... I bring it here
because the CFE Devs told me to do this a long time ago (cf.,
http://clang-developers.42468.n3.nabble.com/Suggestion-for-C-migration-tool-tr1-removal-td4030729.html),
and Marshall Clow stated TR1 is no longer since C++11 (cf.,
http://marshall.calepin.co/c-and-xcode-46.html).

#if (__cplusplus >= 201103L) // C++11
# include <memory>
#elif defined(__APPLE__) // C++03 and Apple
# include <tr1/memory>
#else // C++03 and everyone else
# include <memory>
#endif

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

The above results in a compile failure:

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

How do we manage auto_ptr/unique_ptr on Apple platforms under Clang?
What is the secret sauce I am missing?

Why are you trying to special-case __APPLE__ at all? You might want to have different things for libstdc++ / libc++, but that’s not an Apple/everyone else distinction.

David

Because Apple fiddles with things. I.e., its broke without the Apple
defines, too.

Jeff

Do you have test cases for this? I’ve not encountered any problems moving C++ code between OS X and FreeBSD, the only time I need portability #defines is when I also want to move it to a platform where libstdc++ is the default C++ standard library implementation.

David

My apologies if you were implying I should check based on Clang. Here
are the results based on that, too:

// http://marshall.calepin.co/c-and-xcode-46.html
#if (__cplusplus >= 201103L) // C++11
# include <memory>
#elif defined(__clang__) // C++03 and Clang
# include <tr1/memory>
#else // C++03 and everyone else
# include <memory>
#endif

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

Results in:

./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>;

So its the same issue....

Well, I'm kind of suffering one as we speak :slight_smile:

What would you like me to submit?

Try:

clang -mmacosx-version-min=10.9 -std=c++11 -DNDEBUG -g2 -O3 -fPIC -march=native -Wall -Wextra -pipe -c 3way.cpp

Otherwise it uses the old gcc 4.2 libstc++ headers, for compatibility with OSX 10.8 and below, which don't define std::unique_ptr.

  - ½

Why are you trying to special-case __APPLE__ at all? You might want to have different things for libstdc++ / libc++, but that’s not an Apple/everyone else distinction.

Because Apple fiddles with things. I.e., its broke without the Apple
defines, too.

Do you have test cases for this? I’ve not encountered any problems moving C++ code between OS X and FreeBSD, the only time I need portability #defines is when I also want to move it to a platform where libstdc++ is the default C++ standard library implementation.

Well, I'm kind of suffering one as we speak :slight_smile:

What would you like me to submit?

I think these are the four test cases. Two of them fail...

* c++ -c test-clapple.cxx
    * OK
* c++ -stdlib=libc++ -c test-clapple.cxx
    * FAIL
* c++ -std=c++11 -c test-clapple.cxx
    * FAIL
* c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx
    * OK

By the way, here are my test results:

// c++ -c test-clapple.cxx
// - OK
// c++ -stdlib=libc++ -c test-clapple.cxx
// - FAILS, 'tr1/memory' not found
// c++ -std=c++11 -c test-clapple.cxx
// - FAILS, no type named 'unique_ptr' in namespace 'std'
// c++ -std=c++11 -stdlib=libc++ -c test-clapple.cxx
// - OK

The reason this is a problem for us is auto_ptr is deprecated in
C++11. Our engineering process requires a clean compile with -Wall
-Wextra as a security gate. So we can't pass through the gate until we
sort this out....

(And we don't do things like masking warnings we don't feel like managing).

And here's part of the problem:

    $ c++ -x c++ -dM -E - < /dev/null | grep -i libcpp
    $

Like I said, Apple fiddles with things incessantly....

Jeff

Yes, you keep saying this, and it keeps being wrong (or, at least, completely irrelevant to the problem at hand). You want something like this:

#if __has_include(<tr1/memory>) && (__cplusplus < 201103L)
# include <tr1/memory>
using std::auto_ptr;
#else
# include <memory>
#endif
#if __cplusplus >= 201103L
template<typename T> using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif

This works on FreeBSD, Linux, and Mac OS X and contains no Apple-specific code, because it checks for the thing that you actually want to check (sort of - you may want to prefer unique_ptr if you’re using a C++11 standard library. If so, rearrange the tests to put the C++11 check first) and not some random

If you also want this to work with g++, then you’ll need to add another case for that, as most g++ versions don’t support __has_include (I think the latest ones do). You can stick this in a configure-time check if you need to.

And you can then deal with the fallout from having different ABIs for C++11 and C++03 if anyone links against your code.

David

Like I said, Apple fiddles with things incessantly....

Yes, you keep saying this, and it keeps being wrong

My apologies.

Something is not right here, and I'm frustrated that I have wasted
hours on something that should have taken minutes.

... You want something like this:

#if __has_include(<tr1/memory>) && (__cplusplus < 201103L)
# include <tr1/memory>
using std::auto_ptr;
#else
# include <memory>
#endif
#if __cplusplus >= 201103L
template<typename T> using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif

This fails under test case 3 for me. That's the one:

    c++ -std=c++11 -c test-clapple.cxx

Below are the results and the test program again.