Я работаю над большим программным приложением, которое должно работать на нескольких платформах. Некоторые из этих платформ поддерживают некоторые функции C ++ 11 (например, MSVS 2010), а некоторые не поддерживают какие-либо (например, GCC 4.3.x). Я ожидаю, что эта ситуация будет продолжаться в течение нескольких лет (мое лучшее предположение: 3-5 лет).
Учитывая это, я хотел бы настроить интерфейс совместимости таким образом, чтобы (насколько это было возможно) люди могли писать код на C ++ 11, который все равно будет компилироваться со старыми компиляторами с минимальным обслуживанием. В целом, цель состоит в том, чтобы минимизировать # ifdef настолько, насколько это возможно, при этом поддерживая базовый синтаксис / функции C ++ 11 на платформах, которые их поддерживают, и обеспечивать эмуляцию на платформах, которые этого не делают.
Давайте начнем с std :: move (). Самый очевидный способ достижения совместимости - поместить что-то вроде этого в общий заголовочный файл:
#if !defined(HAS_STD_MOVE)
namespace std { // C++11 emulation
template <typename T> inline T& move(T& v) { return v; }
template <typename T> inline const T& move(const T& v) { return v; }
}
#endif // !defined(HAS_STD_MOVE)
Это позволяет людям писать такие вещи, как
std::vector<Thing> x = std::move(y);
... безнаказанно. Он делает то, что они хотят в C ++ 11, и он делает все возможное, в C ++ 03. Когда мы наконец отбросим последний из компиляторов C ++ 03, этот код может остаться как есть.
Однако, согласно стандарту, вводить новые символы в std
пространство имен незаконно . Это теория. Мой вопрос: практически говоря, есть ли какой-то вред в этом как способ достижения прямой совместимости?
Ответы:
Я долгое время работал над поддержанием уровня прямой и обратной совместимости в моих программах на C ++, пока мне, в конечном счете, не пришлось делать из этого библиотечный инструментарий , который
я готовлю к выпуску, уже выпущен. В общем, до тех пор, пока вы принимаете, что вы не получите «идеальной» прямой совместимости ни в функциях (некоторые вещи просто не могут быть эмулированы в прямом направлении), ни в синтаксисе (вам, вероятно, придется использовать макросы, альтернативные пространства имен для некоторые вещи) тогда у вас все готово.Существует множество функций, которые можно эмулировать в C ++ 03 на уровне, достаточном для практического использования, и без всяких хлопот, которые возникают, например: Boost. Черт, даже предложение по стандартам C ++
nullptr
предлагает бэкпорт C ++ 03. И еще есть TR1, например, для всего C ++ 11, но «у нас были предварительные просмотры» в течение многих лет. Мало того, некоторые функции C ++ 14, такие как варианты assert, прозрачные функторы иoptional
могут быть реализованы в C ++ 03!Единственные две вещи, которые я знаю, которые не могут быть полностью перенесены, - это шаблоны constexpr и variadic.
Что касается всего вопроса добавления чего-либо в пространство имен
std
, я считаю, что это не имеет значения - вообще. Вспомните Boost, одну из наиболее важных и актуальных библиотек C ++, и их реализацию TR1: Boost.Tr1. Если вы хотите улучшить C ++, сделать его более совместимым с C ++ 11, то по определению вы превращаете его в нечто, не являющееся C ++ 03, поэтому блокирование себя над стандартом, которого вы намерены избегать или оставить позади, в любом случае Проще говоря, контрпродуктивно. Пуристы будут жаловаться, но по определению не нужно заботиться о них.Конечно, то, что вы не будете следовать (03) Стандарту, вовсе не означает, что вы не можете попытаться или будете радостно его нарушать. Не в этом дело. До тех пор, пока вы очень тщательно следите за тем, что добавляется в
std
пространство имен, и имеете контроль над средами, в которых используется ваше программное обеспечение (т. Е .: проводите тестирование!), Никакого необратимого вреда не должно быть вообще. Если возможно, определите все в отдельном пространстве имен и добавьте толькоusing
директивы в пространство имен,std
чтобы вы не добавляли туда ничего, кроме того, что «абсолютно» нужно было бы ввести. Что, IINM, более или менее то, что делает Boost.TR1.Обновление (2013) : в качестве запроса исходного вопроса и просмотра некоторых комментариев, которые я не могу добавить из-за отсутствия повторений, приведен список функций C ++ 11 и C ++ 14 и их степень переносимости. до C ++ 03:
nullptr
: полностью реализуемо с учетом официального бэкпорта комитета; вам, вероятно, придется также предоставить некоторые специализации type_traits, чтобы он распознавался как «нативный» тип.forward_list
: полностью реализуемо, хотя поддержка распределителя зависит от того, что может обеспечить ваша реализация Tr1.vector<int> v = {1, 2, 3, 4};
: полностью реализуемы, хотя и более многословны, чем хотелось бы.static_assert
: почти полностью реализуемо при реализации в виде макроса (вам нужно быть осторожным только с запятыми).unique_ptr
: почти полностью реализуем, но вам также понадобится поддержка вызова кода (для хранения их в контейнерах и т. д.); смотрите ниже, хотя.static_cast<>
может быть почти невозможна.noexcept
: зависит от возможностей вашего компилятора.auto
семантика иdecltype
: зависит от особенностей вашего компилятора - например .:__typeof__
.int16_t
и т. д.): зависит от возможностей вашего компилятора или вы можете делегировать его в Portable stdint.h.::type
всегда были шаблоныconstexpr
Насколько мне известно, это невозможно осуществить.dynarray
: полностью реализуемо.optional<>
: практически полностью реализуем, если ваш компилятор C ++ 03 поддерживает настройки выравнивания.std::less<void>
чтобы заставить его работать.assure
): полностью реализуемых, если вы хотите утверждений , почти полностью реализуемых, если вы хотите вместо этого включить броски.(Отказ от ответственности: некоторые из этих функций реализованы в моей библиотеке бэкпортов C ++, которую я связал выше, поэтому я думаю, что знаю, о чем говорю, когда говорю «полностью» или «почти полностью».)
источник
Это принципиально невозможно. Посмотрим
std::unique_ptr<Thing>
. Если бы можно было эмулировать ссылки на rvalue как библиотеку, это не было бы языковой особенностью.источник
std::unique_ptr
это, но некоторые другие функции ссылок на rvalue не могут быть реализованы в C ++ 03, поэтомуstd::forward
это невозможно. Другое дело, чтоstd::unique_ptr
они не будут полезны, потому что коллекции не будут использовать семантику перемещения, если вы не замените их все.unique_ptr
. Посмотрите на недостаткиauto_ptr
.unique_ptr
это практически учебный пример класса, семантика которого была в основном включена языковой особенностью.unique_ptr
то, что было в основном включено языковой функцией. Это было бы не очень полезно без этой функции. потому что без идеальной пересылки во многих случаях это было бы бесполезно, а для идеальной пересылки требуется эта функция.-std=c++0x
опцию, чтобы включить их).std
пространство имен - это «неопределенное поведение». Это означает, что в спецификации не сказано, что произойдет. Но если вы знаете, что на конкретной платформе стандартная библиотека не определяет что-то, просто определитесь. Просто ожидайте, что вам придется проверить на каждой платформе, что вам нужно и что вы можете определить.unique_ptr
. Однако, это не было бы слишком полезно, потому что оно опирается на коллекции, фактически использующие семантику перемещения, а C ++ 03, очевидно, не будет.источник