В чём разница между decltype(auto)
и auto&&
?
Понятно, что типы вычисляются по разным механизмам, но есть ли разница в конечном результате?
Раз типы вычисляются по разным механизмам, то и разница в конечном результате присутствует, иначе зачем тогда было бы два способа (хотя в С++ куча мест где без причин есть несколько способов сделать одно и то же)?
#include <type_traits>
class foo {};
foo bar() { return foo{}; }
decltype(auto) var1{bar()};
auto && var2{bar()};
static_assert(::std::is_same_v<decltype(var1), class foo>);
static_assert(::std::is_same_v<decltype(var2), class foo &&>);
Безусловно разница есть, но в некоторых случаях могут быть и одинаковые результаты. Ничего удивительного в том, что разные подходы могут при некотором стечении обстоятельств давать одинаковые результаты быть не должно. Пример:
#include <type_traits>
int& f()
{
static int i = 42;
return i;
}
int g() { return 42; }
int main()
{
auto&& v1 = f();
decltype(auto) v2 = f();
auto&& v3 = g();
decltype(auto) v4 = g();
static_assert(std::is_same<decltype(v1), int&>::value);
static_assert(std::is_same<decltype(v2), int&>::value);
static_assert(std::is_same<decltype(v3), int&&>::value);
static_assert(std::is_same<decltype(v4), int>::value);
}
Для переменной, используемой в качестве результата f()
и auto&&
и decltype(auto)
дадут одинаковые типы - int&
. С функцией g()
уже будут другие результаты - int&&
и int
соответственно.
decltype(auto)
даёт тип объявления сущности, т.е. в случае функций объявленный тип результата: int&
для f()
, и int
для g()
. Подробнее можно посмотреть тут.
В свою очередь вывод для auto&&
будет работать по схеме вывода типа параметра в шаблоне следующего вида:
template <class T>
void t(T&& a); // T вместо auto
Если вызвать t(f())
то тип a
будет выведен как int&
, а для t(g())
получится int&&
.
Выражение вида auto&& foo = make_foo(params);
будет корректно в большинстве случаев, за исключением некоторых прокси-объектов. Если make_foo
возвращает тип bar
, foo
будет иметь тип bar&&
, при этом время жизни возвращаемого значения будет расширено до времени жизни foo
. Т.е. это корректно, как и в таком случае:
std::string&& str = std::string("foo");
std::string str2 = std::move(str);
Если make_foo
возвращает bar&
, const bar&
или const bar&
, foo
будет иметь соответствующий тип. Это полезно, например, при работе с кортежами:
std::tuple<bar&, const bar&, bar&&> t = ...;
auto&& r1 = std::get<0>(t); // bar&
auto&& r2 = std::get<1>(t); // const bar&
auto&& r3 = std::get<2>(t); // bar&&
В случае decltype(auto)
это перестаёт работать. В выражении decltype(auto) foo = make_foo(params);
, если make_foo
возвращает bar
, foo
будет иметь тип bar
, т.е. значение будет сразу перемещено или будет применена оптимизация возвращаемого значения, что не всегда желательно.
Пример:
auto&& foo= makeBar(); // Bar&&
// перемещение или инициализация на месте, Эквивалентно vector.emplace_back(makeBar())
vector.emplace_back(foo);
Или
decltype(auto) baz = makeBar(); // Перемещение или инициализация на месте
vector.emplace_back(baz); // Копирование
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Пытаюсь получить транспонированную матрицу, но выдает ошибку Выражение должно иметь константное значение n, m; Не могу понять что не так, пример...
Возможно ли использовать импортируемые dll (имеющие расширениеpyd) в питоне на Windows без линковки к pythonXX
Пытаюсь задать название библиотеки, используя generator expressions, однако получаю ошибку сборки:
Создал класс, который реализует массив на shared_ptrХочу перегрузить операцию равно, внутри метода все работает - массив получает новый размер...