В чем разница между присваиванием 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, но все компиляторы дают тот же результат.
Ответы
Ответ 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
предполагает, что он, вероятно, правильный.