decltype, универсальные ссылки и пересылка для контейнеров в C ++ - PullRequest
0 голосов
/ 03 апреля 2019

Я читаю о decltype и ссылках rvalue в эффективной современной C ++ книгой Скотта Мейерса.У меня есть следующий код

template <typename container, typename index>
decltype(auto) authAndAccess(container&& c, index i)  {
    std::cout << "auth and Access c type: " << typeid(c[i]).name() << std::endl;
    std::cout << "auth and Access c type expecting reference: " << typeid(std::forward<container>(c)[i]).name() << std::endl;
    return std::forward<container>(c)[i];
}

deque<int> makeStringDeque() {
    deque<int> dqContainer = { 1,2,3,4,5 };
    return dqContainer;
}

теперь в основной функции У меня есть следующий

deque<int> dqContainer = { 1,2,3,4,5 };
std::cout << "Value returned by container: " << authAndAccess(dqContainer, 4) << std::endl;
authAndAccess(deque<int>{1, 2, 3, 4, 5}, 4) = 10;
std::cout << "Value returned by container and 5th element after copying: " << dqContainer[4] << endl;

Мой вопрос: authAndAccess функция принимает аргумент rvalue, поэтому контейнер является временным, а возвращение является объектом является временной ссылкойэлемент.Но почему вывод отображается как int для typeid переадресации, для которой я ожидаю int &.Я понимаю, что функция name typeid не точна, но почему она не падает, так как мы возвращаем временную ссылку на элемент.

1 Ответ

2 голосов
/ 03 апреля 2019

Мой вопрос: authAndAccess функция принимает аргумент rvalue, поэтому контейнер является временным, а возвращаемый объект является временным ссылочным элементом.

authAndAccess принимает то, что Скотт назвал универсальной ссылкой, которая теперь называется ссылкой пересылки, поэтому она может принимать аргументы lvalue и rvalue.Когда вы передаете ему lvalue, вы получаете ссылку lvalue, а когда вы передаете ему значение rvalue, вы получаете ссылку rvalue.std::forward<container> делает то же самое.Если container является lvalue, вы получаете lvalue, а для rvalue вы получаете rvalue.

Это означает, что authAndAccess(dqContainer, 4) хорошо, так как вы возвращаете ссылку на объект в dqContainer, который все еще существует.В authAndAccess(makeStringDeque(), 4) вы можете подумать, что у вас неопределенное поведение, поскольку makeStringDeque() является временным, и вы возвращаете ссылку на него, но, поскольку вы не сохраняете его, UB не существует, так как ссылка будет действительна до концаполное выражение.


Но почему вывод отображается как int для typeid переадресации, для которой я ожидаю int &.

typeid не скажу, есть ли у вас ссылка.Вы можете видеть это в этом минимальном примере

int main(int argc, char* argv[])
{
    int a = 5;
    int & b = a;
    std::cout << typeid(b).name();
}

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

template<typename T>
struct type;

int main(int argc, char* argv[])
{
    int a = 5;
    int & b = a;
    type<decltype(b)>{};
}

, мы получим ошибку типа

main.cpp:14:5: error: implicit instantiation of undefined template 'type<int &>'
    type<decltype(b)>{};

и, как вы можете видеть, выводит тип как int &.Если мы сделаем это в вашем коде, это также даст int &, поскольку это тип возврата c[i].

...