Почему использование кортежей в C ++ не является более распространенным?

StackOverflow https://stackoverflow.com/questions/855110

  •  21-08-2019
  •  | 
  •  

Вопрос

Почему, похоже, никто не использует кортежи в C ++, ни Увеличить библиотеку кортежей или стандартная библиотека для 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);

Кортежи также значительно упрощают возврат нескольких переменных из функции, что, вероятно, является гораздо более распространенным случаем, чем обмен значениями.Использование ссылок для возврата значений, безусловно, не очень элегантно.

Есть ли какие-то большие недостатки у кортежей, о которых я не думаю?Если нет, то почему они редко используются?Они медленнее?Или это просто потому, что люди к ним не привыкли?Хорошая ли идея использовать кортежи?

Это было полезно?

Решение

Потому что это еще не стандартно.Все нестандартное сопряжено с гораздо более высокими препятствиями.Части Boost стали популярными, потому что программисты требовали их.(на ум сразу приходит hash_map).Но хотя tuple удобен, это не такая уж ошеломляющая и очевидная победа, чтобы люди беспокоились об этом.

Другие советы

Циничный ответ заключается в том, что многие люди программируют на C ++, но не понимают и / или не используют функциональность более высокого уровня.Иногда это происходит потому, что им не разрешают, но многие просто не пытаются (или даже не понимают).

В качестве примера без повышения:сколько людей используют функциональность, найденную в <algorithm>?

Другими словами, многие программисты на C ++ - это просто программисты на C, использующие компиляторы C ++, и, возможно std::vector и std::list.Это одна из причин, по которой использование boost::tuple не является более распространенным явлением.

Синтаксис кортежей C ++ может быть немного более подробным, чем хотелось бы большинству людей.

Рассмотреть:

typedef boost::tuple<MyClass1,MyClass2,MyClass3> MyTuple;

Так что, если вы хотите широко использовать кортежи, вы либо получаете везде 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-tuple становится меньше кода, чем n-1 swaps.И при замене по умолчанию это выполняет 6 назначений вместо 4, которые у вас были бы, если бы вы самостоятельно реализовали шаблон с тремя циклами, хотя я надеюсь, что компилятор решит это для простых типов.

Вы можете придумать сценарии, в которых обмены являются громоздкими или неуместными, например:

tie(a,b,c) = make_tuple(b*c,a*c,a*b);

немного неудобно распаковывать.

Дело в том, однако, что существуют известные способы решения наиболее распространенных ситуаций, для которых подходят кортежи, и, следовательно, нет особой срочности в использовании кортежей.Во всяком случае, я не уверен, что:

tie(a,b,c) = make_tuple(b,c,a);

не делает 6 копий, что делает его совершенно непригодным для некоторых типов (коллекции являются наиболее очевидными).Не стесняйтесь убеждать меня, что кортежи - хорошая идея для "больших" типов, говоря, что это не так :-)

Для возврата нескольких значений кортежи идеальны, если значения имеют несовместимые типы, но некоторым пользователям они не нравятся, если вызывающий может получить их в неправильном порядке.Некоторым людям вообще не нравится несколько возвращаемых значений, и они не хотят поощрять их использование, упрощая их.Некоторые люди просто предпочитают именованные структуры для входных и выходных параметров, и, вероятно, их невозможно убедить бейсбольной битой использовать кортежи.Без учета вкуса.

Как отмечали многие люди, кортежи просто не так полезны, как другие функции.

  1. Трюки с заменой и вращением - это всего лишь трюки.Они совершенно сбивают с толку тех, кто не видел их раньше, и, поскольку это касается практически всех, эти уловки - просто плохая практика разработки программного обеспечения.

  2. Возврат нескольких значений с использованием кортежей гораздо менее самодокументирован, чем альтернативы - возврат именованных типов или использование именованных ссылок.Без этого самодокументирования легко перепутать порядок возвращаемых значений, если они взаимно конвертируемы, и не быть более разумным.

Не каждый может использовать boost, и TR1 пока не получил широкого распространения.

При использовании C ++ во встраиваемых системах использование библиотек Boost становится сложным.Они соединяются друг с другом, поэтому размер библиотеки увеличивается.Вы возвращаете структуры данных или используете передачу параметров вместо кортежей.При возврате кортежей в Python структура данных соответствует порядку и типу возвращаемых значений, которые просто не являются явными.

Вы редко видите их, потому что хорошо продуманный код обычно в них не нуждается - в дикой природе не так много случаев, когда использование анонимной структуры превосходит использование именованной.Поскольку все, что на самом деле представляет собой кортеж, - это анонимная структура, большинство программистов в большинстве ситуаций просто используют реальную вещь.

Допустим, у нас есть функция "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", изменив "ReturnInts" БЕЗ ИЗМЕНЕНИЯ ИНТЕРФЕЙСА "f".Решение tuple не предлагает этой критической функции, что делает его неполноценным решением для любого библиотечного кода.

Конечно, кортежи могут быть полезны, но, как уже упоминалось, это сопряжено с небольшими накладными расходами и одним-двумя препятствиями, которые вам нужно преодолеть, прежде чем вы сможете их по-настоящему использовать.

Если ваша программа постоянно находит места, где вам нужно вернуть несколько значений или поменять местами несколько значений, возможно, стоит пойти по маршруту кортежа, но в остальном иногда просто проще делать что-то классическим способом.

Вообще говоря, не у всех уже установлен Boost, и я, конечно, не стал бы утруждать себя его загрузкой и настройкой моих включенных каталогов для работы с ним только из-за его возможностей использования кортежей.Я думаю, вы обнаружите, что люди, уже использующие Boost, с большей вероятностью найдут применение кортежам в своих программах, чем пользователи, не использующие Boost, а мигранты с других языков (на ум приходит Python), скорее всего, просто расстроятся из-за отсутствия кортежей в C ++, чем изучат методы добавления поддержки кортежей.

В качестве хранилища данных std::tuple обладает наихудшими характеристиками как struct и массив;весь доступ основан на n-й позиции, но невозможно выполнить итерацию через tuple используя for петля.

Итак, если элементы в tuple концептуально являются массивом, я буду использовать массив, и если элементы концептуально не являются массивом, структура (которая имеет именованные элементы) более удобна в обслуживании.( a.lastname является более объяснимым , чем std::get<1>(a)).

Это оставляет преобразование, упомянутое OP, единственным жизнеспособным вариантом использования для кортежей.

У меня такое ощущение, что многие используют Boost.Any и Boost.Variant (с некоторой разработкой) вместо Boost.Кортеж.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top