Подтвердить что ты не робот

В чем разница между присваиванием std:: tie и кортежем ссылок?

Я немного озадачен следующим кортежем:

int testint = 1;
float testfloat = .1f;
std::tie( testint, testfloat ) = std::make_tuple( testint, testfloat );
std::tuple<int&, float&> test = std::make_tuple( testint, testfloat );

С std::tie он работает, но привязка непосредственно к кортежу ссылок не компилируется, давая

": преобразование из 'std:: tuple < int, float > в нескалярный тип' std:: tuple < int &, float & > запрошено"

или

"нет подходящего пользовательского преобразования из std:: tuple < int, float > в std:: tuple < int &, float & > "

Почему? Я дважды проверял с помощью компилятора, если он действительно тот же тип, которому назначается, делая это:

static_assert( std::is_same<decltype( std::tie( testint, testfloat ) ), std::tuple<int&, float&>>::value, "??" );

Что оценивается как истина.

Я также проверил онлайн, чтобы узнать, может ли это быть ошибкой msvc, но все компиляторы дают тот же результат.

4b9b3361

Ответ 1

Функция std::tie() фактически инициализирует члены std::tuple<T&...> ссылок, где std::tuple<T&...> не может быть инициализирована шаблоном std::tuple<T...>. Операция std::tie() делает, и инициализация соответствующего объекта будет выражаться следующим образом:

std::tuple<int&, float&> test = 
    std::tuple<int&, float&>(testint, testfloat) = std::make_tuple(testint, testfloat);

(очевидно, вы обычно используете разные значения, чем те, которые уже связаны с переменными).

Ответ 2

Оба make_tuple и tie выводят возвращаемый тип аргументами. Но tie сделает ссылочный тип lvalue в соответствии с выведенным типом, а make_tuple сделает фактический кортеж.

std::tuple<int&, float&> a = std::tie( testint, testfloat );

std::tuple<int , float > b = std::make_tuple( testint, testfloat );

 

Цель tie заключается в создании временного кортежа, чтобы избежать временных копий связанных объектов, плохой эффект, вы не можете return a tie, если объекты ввода являются локальными временными.

Ответ 3

Проблема заключается в том, что rhs std::make_tuple(testint, testfloat) не возвращает массив ссылок, он возвращает std::tuple<int, int>, который является временным, чьи значения не могут связываться с lvalue-ссылками. Если вам нужен кортеж ссылок, вы можете использовать вспомогательную функцию std::ref:

auto test = std::make_tuple(std::ref(a), std::ref(b));
//                          ^^^^^^^^^^^  ^^^^^^^^^^^

Разница между этим и tie заключается в том, что ссылки инициализируются std::tie(a, b) при построении.

Ответ 4

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

Проверка кода

#include <tuple>
#include <iostream>

int main() {

    std::tuple<int> a{};

    std::cout << std::get<0>(a) << std::endl;

    std::tuple<float> b{1.f}; //note float type

    a = b;

    std::cout << std::get<0>(a) << std::endl;

}
output: 0 1

предполагает, что он, вероятно, правильный.