2016-03-18 3 views
3

Я знаю, что std::tuple является допустимым способом возврата нескольких переменных разных типов из функции, как указано в a talk by Herb Sutter примерно в 1:31:00 (Этот пример кода - мой, а не из видео)C++ Возвращаемые множественные значения с помощью Struct

auto get_tuple() 
{ 
    return std::make_tuple(1, 2); 
} 

затем "распаковывать" это либо

auto t = get_tuple(); 
int a = std::get<0>(t); 
int b = std::get<1>(t); 

или

int a; 
int b; 
std::tie(a, b) = get_tuple(); 

Эти методы отличные, но мне не особенно нравится синтаксис std::get или std::tie. Я бы не стал использовать полезный инструмент только из-за уродливого синтаксиса (по моему личному мнению), но как насчет этого?

auto get_struct() 
{ 
    struct R 
    { 
    int a; 
    int b; 
    } 

    return R{1, 2}; 
} 

Это компилируется для меня (Visual Studio 2015), и мне больше нравится его синтаксис. Я не хочу, чтобы меня обвиняли в преждевременной оптимизации, но я также упомянул, что это во много раз быстрее, чем кортеж. В основном мне нравится синтаксис.

Тем не менее, я знаю, что только потому, что компиляция не означает, что язык предназначен для использования таким образом. Я не совсем уверен, как сформулировать этот вопрос, но в основном, это действительное и определенное поведение? Могу ли я быть уверенным, что это будет работать на других крупных компиляторах? Честно говоря, я был довольно удивлен, что он будет выводить тип, даже если этот тип определен в самой функции, поэтому я хочу убедиться, что все в порядке.

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

EDIT: Как указано в ответах, мое утверждение о том, что локальная структура во много раз быстрее, чем кортеж, совершенно неверна. Я не делал свой тест должным образом. См. Ответы для большего, я просто хотел изменить это, чтобы убедиться, что я никого не вводит в заблуждение.

+1

Я согласен с ниже ответ, имеющие классы вместо встроенного в типах, вероятно, будет иметь значение с точки зрения производительности. Я хотел бы получить аргументы типа 'void get_tuple (int & out1, int &out2);' или даже более общий 'void get_values ​​(std :: vector & values); '- этот способ может получить любое количество значений. – Alex

+1

Вы уверен, что вы не измеряете его в режиме отладки? С включенной оптимизацией кортежи не должны заметно замедляться. – SergeyA

+0

Что вы подразумеваете под словом «кажется, что это во много раз быстрее, чем кортеж». Что такое «это»? – Barry

ответ

4

Хотя локальная структура стандартно совместима, я советую ее не использовать (в отличие от кортежей). Прежде всего, показатель эффективности, скорее всего, неверен.

следующий код:

#include <tuple> 

auto get_tuple() 
{ 
    auto tup = std::make_tuple(1.0f, 2.0f); 
    return tup; 
} 

auto get_struct() { 
    struct R { 
    float a, b; 
    }; 

    return R{1, 2}; 
} 

Производит следующие ASM в оптимизированном режиме:

get_tuple(): 
     movq %rdi, %rax 
     movl $0x40000000, (%rdi) 
     movl $0x3f800000, 4(%rdi) 
     ret 
get_struct(): 
     movq .LC3(%rip), %xmm0 
     ret 
.LC3: 
     .quad 4611686019492741120 

Так что это только два movl инструкции больше. Я не думаю, что можно измерить эффект этого.

И кортеж просто дает гораздо больше, чем структура! Вы можете знать, что это размер с точки зрения элементов (во время компиляции). Вы можете соединить кортежи. Вы можете построить на них систему отражения. Вы можете использовать их с std::tie. Вы можете указать их тип. (С локальной структурой это будет автоматически все вниз). В локальных структурах ничего подобного нет.

+1

'struct' позволяет лучше называть, чем' get <3> (t) '. (Предполагая, что имена лучше, чем 'a',' b' ;-)). Если это не общий код, я бы предпочел бы структуру. – Jarod42

1

Это правильное поведение, и вы правы, что это быстрее, чем использование кортежа. Однако вы используете простой корпус со встроенными типами. Различия в производительности с использованием std::tuple и struct с пользовательскими типами могут сделать использование std::tuple более привлекательным, несмотря на менее элегантный синтаксис.

+1

* * вы правы, что это быстрее, чем использование кортежа * '- на что вы основываете это утверждение? – SergeyA

+0

@SergeyA Это был мой эксперимент что templatized код накладывает накладные расходы, даже со встроенными типами. – TriskalJM

3

[...] Это действительное и определенное поведение?

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

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

Я скептически, что производительность выполнения должна отличаться от локальной структуры, состоящей из двух int с и std::tuple<int, int>. Время компиляции, конечно, tuple будет медленнее.

Так как только вы вернуть экземпляр локального класса, это не действительно местные, вы можете просто сделать это не локальный класс:

struct R { ... }; 
R get_struct(); 

Тогда есть еще менее вопрос о том или нет, это что действительный.

Кроме того, вы всегда можете напрямую подключить свой кортеж к тому, что его распакует. Проверьте Yakk's answer что-то вроде:

std::tuple<int, int> get_tuple(); 

unpack(get_tuple(), [](int i, int j) { ... }); 
get_tuple() *then* [](int i, int j){ ... }; 

Вы также можете быть счастливы знать, что есть structured bindings proposal, которые бы непосредственно позволяют:

auto {a, b} = get_tuple(); 
Смежные вопросы