Почему использование кортежей в C++ не более распространено?
Почему никто, кажется, не использует кортежи в C++, либо Boost Tuple Library или стандартная библиотека для TR1? Я прочитал много кода на C++, и очень редко я вижу использование кортежей, но я часто вижу много мест, где Кортежи будут решать многие проблемы (обычно возвращая несколько значений из функций).
кортежи позволяют делать все виды крутых вещей, как это:
tie(a,b) = make_tuple(b,a); //swap a and b
это, конечно, лучше, чем это:
temp=a;
a=b;
b=temp;
конечно, вы всегда можете сделать это:
swap(a,b);
но что, если вы хотите повернуть три значения? Вы можете сделать это с кортежами:
tie(a,b,c) = make_tuple(b,c,a);
кортежи также значительно упрощают возврат нескольких переменных из функции, что, вероятно, является гораздо более распространенным случаем, чем замена значений. Используя ссылки на возвращаемые значения, конечно, не очень элегантно.
есть ли какие-то большие недостатки кортежей, о которых я не думаю? Если нет, то почему они редко используются? Они медленнее? Или просто люди к ним не привыкли? Это хорошая идея, чтобы использовать кортежи?
12 ответов:
потому что это не стандарт. Все нестандартное имеет гораздо более высокий барьер. Части повышения стали популярными, потому что программисты требовали их. (hash_map приходит на ум). Но в то время как кортеж удобен, это не такая подавляющая и ясная победа, что люди беспокоятся об этом.
циничный ответ заключается в том, что многие люди программируют на C++, но не понимают и/или не используют функциональность более высокого уровня. Иногда это происходит потому, что их не пускают, но многие просто не пытаются (или даже не понимают).
в качестве примера без повышения: сколько людей используют функциональность, найденную в
<algorithm>?другими словами, многие программисты на C++ - это просто программисты на C, использующие компиляторы C++, и, возможно,
std::vectorиstd::list. Это одна из причин, почему использованиеboost::tuple- это не более распространенный.
синтаксис кортежа C++ может быть довольно многословным, чем хотелось бы большинству людей.
считаем:
typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;поэтому, если вы хотите широко использовать кортежи, вы либо получаете tuple typedefs везде, либо получаете раздражающе длинные имена типов везде. Мне нравятся кортежи. Я использую их, когда это необходимо. Но это обычно ограничивается несколькими ситуациями, такими как индекс N-элемента или при использовании multimaps для привязки пар итераторов диапазона. И это, как правило, в очень ограниченном масштаб.
все это очень некрасиво и хаки выглядит по сравнению с чем-то вроде Haskell или Python. Когда C++0x доберется сюда, и мы получим кортежи ключевых слов "auto", они начнут выглядеть намного привлекательнее.
полезность кортежей обратно пропорциональна количеству нажатий клавиш, необходимых для их объявления, упаковки и распаковки.
для меня это привычка, руки вниз: кортежи не решают никаких новых проблем для меня, только некоторые из них я уже могу справиться просто отлично. Обмен ценностями по-прежнему чувствует себя проще старомодным способом-и, что более важно, я действительно не думаю о том, как поменять "лучше.-Он и так достаточно хорош.
лично я не думаю, что кортежи являются отличным решением для возврата нескольких значений-звучит как работа для
structs.
но что, если вы хотите повернуть три значения?
swap(a,b); swap(b,c); // I knew those permutation theory lectures would come in handy.хорошо, поэтому с 4 значениями etc, в конечном итоге N-кортеж становится меньше кода, чем N-1 свопов. И с помощью свопа по умолчанию это делает 6 назначений вместо 4, которые у вас были бы, если бы вы сами реализовали трехцикловый шаблон, хотя я надеюсь, что компилятор решит это для простых типов.
вы можете придумать сценарии, где свопы громоздки или неуместны, для пример:
tie(a,b,c) = make_tuple(b*c,a*c,a*b);немного неудобно распаковывать.
дело в том, однако, что существуют известные способы решения наиболее распространенных ситуаций, в которых кортежи хороши, и, следовательно, нет большой срочности для принятия кортежей. Если ничего другого, я не уверен, что:
tie(a,b,c) = make_tuple(b,c,a);не делает 6 копий, что делает его совершенно непригодным для некоторых типов (коллекции являются наиболее очевидными). Не стесняйтесь убеждать меня, что кортежи-хорошая идея для "больших" типов, говоря, что это не так Итак: -)
для возврата нескольких значений, кортежи идеально подходят, если значения несовместимых типов, но некоторые люди не любят их, если это возможно для вызывающего абонента, чтобы получить их в неправильном порядке. Некоторые люди вообще не любят несколько возвращаемых значений и не хотят поощрять их использование, упрощая их. Некоторые люди просто предпочитают именованные структуры для входных и выходных параметров, и, вероятно, их нельзя было убедить с помощью бейсбольной биты использовать кортежи. Без учета вкуса.
как указывали многие люди, кортежи просто не так полезны, как другие функции.
подкачки и вращающиеся трюки-это просто трюки. Они совершенно сбивают с толку тех, кто не видел их раньше, и поскольку это почти все, эти трюки-просто плохая практика разработки программного обеспечения.
возврат нескольких значений с помощью кортежей гораздо менее самодокументирован, чем альтернативы -- возврат именованных типов или использование именованных ссылок. Без этого самодокументирования легко перепутать порядок возвращаемых значений, если они взаимно конвертируемы, и не быть мудрее.
при использовании C++ на встроенных системах, вытягивание в библиотеках Boost становится сложным. Они соединяются друг с другом, поэтому размер библиотеки растет. Вы возвращаете структуры данных или используете передачу параметров вместо кортежей. При возврате кортежей в Python структура данных находится в порядке и тип возвращаемых значений его просто не явный.
конечно, кортежи могут быть полезны, но, как уже упоминалось, есть немного накладных расходов и препятствие или два, которые вам нужно перепрыгнуть, прежде чем вы сможете их использовать.
Если ваша программа последовательно находит места, где вам нужно вернуть несколько значений или поменять местами несколько значений, возможно, стоит пойти по маршруту кортежа, но в противном случае иногда просто проще делать все классическим способом.
вообще говоря, не у всех уже установлен Boost, и я конечно, не будет проходить через хлопоты по его загрузке и настройке моих каталогов include для работы с ним только для его кортежей. Я думаю, вы обнаружите, что люди, уже использующие Boost, с большей вероятностью найдут использование кортежей в своих программах, чем пользователи без Boost, а мигранты из других языков (на ум приходит Python), скорее всего, просто расстроятся из-за отсутствия кортежей в C++, чем исследовать методы добавления поддержки кортежей.
вы редко видите их, потому что хорошо разработанный код обычно не нуждается в них-в дикой природе не так много случаев, когда использование анонимной структуры превосходит использование именованной. Поскольку все, что кортеж действительно представляет собой анонимную структуру, большинство кодеров в большинстве ситуаций просто идут с реальной вещью.
скажем, у нас есть функция "f", где возврат кортежа может иметь смысл. Как правило, такие функции обычно достаточно сложны, чтобы они могли выйти из строя.
Если "f" может потерпеть неудачу, вам нужно вернуть статус - в конце концов, вы не хотите, чтобы абоненты должны были проверять каждый параметр для обнаружения сбоя. "f", вероятно, вписывается в шаблон:
struct ReturnInts ( int y,z; } bool f(int x, ReturnInts& vals); int x = 0; ReturnInts vals; if(!f(x, vals)) { ..report error.. ..error handling/return... }это не очень красиво, но посмотрите, насколько уродлива альтернатива. Обратите внимание, что мне все еще нужно значение статуса, но код не более читабелен и не короче. Вероятно, это тоже медленнее, так как я несу стоимость 1 копии с кортежем.
std::tuple<int, int, bool> f(int x); int x = 0; std::tuple<int, int, bool> result = f(x); // or "auto result = f(x)" if(!result.get<2>()) { ... report error, error handling ... }еще один, существенный недостаток скрыт здесь-с "ReturnInts "я могу добавить Alter"f "'s return путем изменения" ReturnInts "без изменения интерфейса"f". Решение кортежа не предлагает эту критическую функцию, что делает его худшим ответом для любого кода библиотеки.
как хранилище данных
std::tupleимеет худшие характеристикиstructи массив; весь доступ основан на N-й позиции, но нельзя перебиратьtupleС помощьюforпетли.так что если элементов
tupleявляются концептуально массивом, я буду использовать массив, и если элементы не являются концептуально массивом, структура (которая имеет именованные элементы) является более поддерживаемой. (a.lastnameболее толковый, чемstd::get<1>(a)).это оставляет преобразование, упомянутое OP как единственный жизнеспособный usecase для кортежей.
У меня такое чувство, что многие используют Boost.Любой и подталкивает.Вариант (с некоторой инженерией) вместо повышения.Кортеж.
Comments