Penso di essermi trovato in una situazione in cui le cose stanno rapidamente andando fuori controllo e vorrei ricevere un feedback per selezionare un modo per procedere.
SFONDO
Sto lavorando con una libreria basata su C ++ 03. La libreria è multipiattaforma e supporta più compilatori. Non ci sono dipendenze o prerequisiti esterni (ad esempio, non è necessario per Autotools, Cmake, Boost, ecc.). Abbiamo iniziato a testare con std=c++11
e abbiamo trovato alcune cose da correggere. Ad esempio, auto_ptr
è stato deprecato, quindi abbiamo dovuto passare a unique_ptr
se __cplusplus >= 201103L
.
Il passaggio a unique_ptr
è stato relativamente facile, tranne su OS X. OS X pubblicizza __cplusplus
come 201103L
, ma è una libreria di runtime C ++ 11 estremamente carente (non ho intenzione di usare il parola "standard" in quella frase). Peggio ancora, se qualcuno costruisce l'ultimo LLVM / Clang da sorgenti su OS X senza libcxx , allora esistono le stesse carenze perché il nuovo Clang usa le vecchie librerie.
Per risolvere il problema di auto_ptr
, siamo passati attraverso alcuni cerchi che terminavano con il seguente codice. Mentre il codice sotto sembra pulito, il preprocessore sta funzionando fuori orario per determinare quando deve definire MYLIB_HAVE_UNIQUE_PTR
e MYLIB_HAVE_TEMPLATE_ALIAS
a causa di OS X.
// The result is MyLib::auto_ptr in both cases
#if defined(MYLIB_HAVE_UNIQUE_PTR) && defined(MYLIB_HAVE_TEMPLATE_ALIAS)
template<typename T>
using auto_ptr = std::unique_ptr<T>;
#else
using std::auto_ptr;
#endif
Stiamo ora cercando di fornire semantica di spostamento protetta su __cplusplus
perché ci sono da due a cinque classi che potrebbero trarne vantaggio. Tuttavia, OS X ci sta dando di nuovo problemi perché manca std::move
. Sospetto che abbia anche problemi con Rvalues e Rvalue References.
Abbiamo chiesto agli sviluppatori di Clang come eseguire il test delle funzioni per std::move
in How per testare std :: move (intersezione di Apple e Clang) . Uno degli sviluppatori di Clang ha suggerito di lanciare il nostro, ma sto iniziando a pensare che sia una battaglia persa basata sul codice sorgente di GNU per move.h . Ad esempio, una rapida grep -IR is_lvalue_reference /usr/include/c++/4.2.1/
non rivela hit.
STRATEGIE
Penso che le nostre scelte siano (1) eliminare del tutto il supporto per OS X; (2) tratta OS X come C ++ 03; (3) implementare la nostra implementazione per le funzionalità mancanti di C ++ 11 su OS X; oppure (4) passare ad Autotools o Cmake per il rilevamento delle funzioni.
(1) non sta per accadere categoricamente. (2) sembra ragionevole. (3) sembra un sacco di lavoro. (4) non accadrà perché introduce delle dipendenze esterne.
Per (2), credo che il test sia facile come:
// For Microsoft's cl.exe, pivot on _MSC_VER, not __cplusplus.
#if (_MSC_VER >= 1600) || (__cplusplus >= 201103L)
# define MYLIB_CXX11 1
#endif
// Ancient C++ runtime library; unset it because its too much trouble.
// Thanks to Jonathan Wakely for the '__has_include(<forward_list>)'
// test. See http://stackoverflow.com/q/31655462.
// TODO: test under Xcode 3, where g++ is really g++.
#if defined(__clang__)
# if !(__has_include(<forward_list>))
# undef MYLIB_CXX11
# endif
#endif
Quindi torna al rilevamento delle caratteristiche canonizzate:
#if MYLIB_CXX11
// Everyone appears to provide this list
#define MYLIB_CXX11_UNIQUE_PTR 1
...
// template aliases: MS at VS 2015 (v19.00); GCC at 4.7; Clang at 3.0; and Intel 12.1.
#if (_MSC_VER >= 1900) || (__INTEL_COMPILER >= 1210)
# define MYLIB_CXX11_TEMPLATE_ALIAS 1
#elif defined(__clang__)
# if (__has_feature(cxx_alias_templates))
# define MYLIB_CXX11_TEMPLATE_ALIAS 1
# endif
#elif (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
# define MYLIB_CXX11_TEMPLATE_ALIAS 1
#endif // template aliases
#endif // MYLIB_CXX11
DOMANDE
Esistono altre strategie per gestire C ++ 11 e OS X?
Qualcuno ha provato la strategia (3)? Se sì, quanto lavoro è stato?
testing
Se hai accesso a OS X, prova a seguire il compilatore incorporato, lo standard e libstdc++
di GNU rispetto a libc++
di LLVM. Successivamente, prova con un compilatore moderno esportando CXX=/opt/local/bin/clang++
.
$ 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;
}