2016-12-21 9 views
0

Я пишу небольшую библиотеку, у которой есть функция API, возвращающая две вещи (разных типов). Я бы предпочел не объявлять структуру только для этого; поэтому я думаю о возвращении std::pair<foo, bat>. Но - возможно, в эти современные времена я предпочитаю вместо этого возвращать std::tuple<foo, bar>?В дизайне API, когда я должен предпочесть длину-2 std :: tuple над парой?

В более общем случае, когда необходимо кортеж над парой, а когда пара - более подходящая конструкция?

+13

В эти современные времена структура с соответствующими именами намного превосходит «std :: pair» с членами с именем «first» и «second», а также с «std :: tuple» с членами named 'get <0>()' и 'get <1>()'. –

+0

, если эти два значения связаны, ex employee id, имя сотрудника, тогда структура будет лучше, на мой взгляд. – ArmenB

+0

Можете ли вы привести пример использования в вашем дизайне API? –

ответ

6

Вы должны объявить для этого структуру.

get<0>(x) и get<1>(x), или даже пост-C++ 11-х get<Foo>(x) и get<Bar>(x), являются менее значимыми и/или идиоматических чем x.foo или x.bar.

tuple s подходит для неравномерно типизированных предметов, которые идентифицируются по заказу.

pair s являются tuple, которые были написаны до C++ 11.

Оба pair и tuplearray пока мы на него) являются кортеж типа, в том, что они поддерживают std::tuple_size и get<N>.

В библиотеке std считается, что так много типов используют pair вместо структур с правильно названными полями. Т.е., если бы map использовал struct KV{ Key key; Value value; }, было бы лучше.

Теперь поддержка метапрограммирования для KV в качестве общей пары была бы хорошей. Итак, tuple_size и get<0> и т. Д. Но выброс названных полей, как правило, плохая идея. Имена имеют власть.

С C++ 17, простые struct s начинают работать со структурированным привязкой, даже если вы не делаете их «кортежированными».

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

0

Но - может быть, в эти современные времена я предпочитаю вместо этого возвращать std::tuple<foo, bar>?

В более общем плане, Когда следует кортеж быть предпочтительным по паре, а когда пара - более подходящая конструкция?

Ну, это может быть полезно в случае, если вы хотите работать с (мета) алгоритмов, а ожидают, чтобы взять std::tuple чем std::pair.

И наконец, это абсолютно зависит от вашего фактического прецедента и на него нельзя ответить, не зная об этом.

Если у вас есть ситуация, которая, по сути, соответствует паре типов (семантически связанных в контексте), вам может быть лучше с std::pair, чтобы отразить эти семантики в API.

Если вы не уверены, скорее используйте std::tuple, чтобы продолжать гибкость дизайна вашего API.

Другим способ просто использовать свои собственные структуры, которые явно были названы семантика значения, как:

template<typename T> 
struct point2D { 
     T x; 
     T y; 
}; 

template<typename T> 
struct point3D { 
     T x; 
     T y; 
     T z; 
}; 

template<typename Key, typename Value> 
struct Item { 
    Key key: 
    Value value; 
}; 

, а не std::tuple<T,T>, std::pair<T,T> или std::tuple<T,T,T>

0

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

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

Это действительно сводится в том, как вы хотите, чтобы все работало и т.д.

+4

Нет, это не то, для чего предназначены пары. Именно так они были неправильно использованы стандартной библиотекой. Если у вас есть пара ключ-значение, то для этой структуры должна быть структура с членом с именем key и членом с именем. –

0

Я часто видел соответствующие вызовы API или библиотеки (математические связанные) возвращают структуры или класса, даже если контейнер имеет два значения.

Но если вам нужно, я согласен с @Bauss, если значение представляет собой пару ключей, тогда используйте std::pair, например «идентификатор таблицы, имя строки».

Но если кортеж не является ключевым значением, но оба являются действительными значениями, например, позиция XY-координата (int x, int y) использует std::tuple.

+0

Ну, это не применяется для использования 'std :: pair', например 2D координатных точек, которые также пользуются популярностью. –

+2

Рамки или lib, которые я использовал до сих пор, никогда не использовали ни 'std :: pair', ни' std :: tuple' для хранения координатных точек. Например, OpenFramework использует Vec2f, Qt использует QPoint, UDK использует FVector2D и т. Д. ... – ArmenB

+0

@ArmenB: ... особенно потому, что пары и кортежи пропускают обычный перегруженный материал, что делает их намного более неудобными для использования в качестве координатных точек. –

0

Внимание: некоторые из того, что следует это мнение:

В информатике, есть только три интересные цифры:

  • нулевой
  • один
  • N

Поскольку мы либо имеем дело с отсутствием чего-то, одного или нескольких вещей. Например, average(a0 , a1) - частный случай average(a0, ...aI), где I - любое целое число в наборе (0 < = I < N).

Из этого следует, что std::pair является логической специализацией N-кортежа и поэтому не нужен.

Хуже, используя pair, предполагается, что количество элементов будет всегда равным 2, и выпекает это в интерфейсе. Это, очевидно, ошибка, так как мы торгуем способностью делать будущие неустойчивые изменения для нулевого выигрыша.

Когда СТЛ впервые была написана не было никаких VARIADIC шаблонов и было только три используют футляры для пар: -

  1. как диапазон в результате equal_range и т.п.

  2. как итератор с состоянием возвращается из map::insert и,

  3. как пара ключ/значение в map.

Затем форсирование сопровождалось его современными идеями, такими как кортежи. Будучи неофициальной библиотекой, boost смог смоделировать вариативные шаблоны со страницами и страницами автогенерированных перегрузок. Что-то, что немыслимо в стандартизованном API, который поставляется с каждым компилятором.

Теперь у нас есть вариативные шаблоны. За исключением случаев, когда, к сожалению, испекли в интерфейсах карт, нет никакой причины предпочесть pair по сравнению с tuple

+1

Даже когда написано STL, решение о возврате 'std :: pair' было очень плохим решением; названная структура была бы намного лучше. 'auto i = map.insert (ключ, значение); if (i.first) {/ * или i.second? никогда не помню ... * /} '. – peppe

+1

"* Хуже того, использование пары предполагает, что количество элементов всегда будет равным 2, и выпекает это в интерфейсе. *« Поскольку функции не испечены по количеству параметров. О, подожди ... "* нет никакой причины предпочитать пару по кортежу *« Если вам не нужен тип, который тривиально можно копировать и/или стандартную компоновку. 'tuple' не является ни тем, ни другим. –

+1

@NicolBolas Это правда, что я не рассматривал этот вариант использования стандартного макета. Однако мне кажется, что в таком случае было бы более выразительно и тривиально просто создать новую структуру, которая выполняла эту работу в трех строках кода (исключая фигурные скобки).Если нам действительно нужны стандартные макеты 2-кортежей, мы можем просто использовать std :: tie вокруг тривиальной структуры и добиться такого же эффекта. Я предлагал предупреждение о наличии мнения. –