Ссылка на пересылку C++ и ссылка на r-значение

Я понимаю, что ссылка на переадресацию — это «ссылка rvalue на параметр шаблона без квалификации cv», например, в

template <class T> void foo(T&& );

что означает, что приведенная выше функция может принимать ссылку как на l-значение, так и на r-значение.

Я что-то не понимаю, например.

template <class T>
class A
{
    template <class U>
    void foo(T&& t, U&& u)
    {
        T t2( std::forward(t) ); // or should it be std::move(t)? is T&& forwarding or r-value reference
        U u2( std::forward(u) ); // or should it be std::move(u)? I believe U&& is forwarding reference
    }
};

в приведенном выше коде являются ли ссылки пересылки T&& и U&&?

Я написал код для тестирования (компилятор VS2015):

class A
{
public:
    A(){};
    A(const A& rhs)
    {
        std::cout << "calling 'const A&' l-value" << std::endl;
    }

    A(A&& rhs)
    {
        std::cout << "calling ' A&&' r-value" << std::endl;
    }

};

template <class T>
class Test
{
public:
    void test1(T&& t)
    {
        T t2(std::forward<T>(t));
    }

    template <typename X>
    void test2(X&& x)
    {
        T t2( std::forward<T>( x ) );
    }

};

void main()
{
    A a;
    Test<A> test;
    test.test1(A());
    test.test1(std::move(a));
    //test.test1(a); // this doesn't compile. error: cannot convert argument 1 from 'A' to 'A &&', You cannot bind an lvalue to an rvalue reference

    test.test2<A>(A());
    test.test2<A>( std::move( a ) );

    //test.test2<A>( a ); // this doesn't compile. error: cannot convert argument 1 from 'A' to 'A &&', You cannot bind an lvalue to an rvalue reference
}

Я ожидал, что test.test1(a); и test.test2(a) должны компилироваться, если они пересылают ссылки, но ни один из них этого не делает.

Может ли кто-нибудь объяснить это мне? Спасибо!

Редактировать --------------спасибо, ребята----------- Ричард и Артемий правы.


person Dave    schedule 01.09.2017    source источник
comment
Безотносительно, я не знаю, грустно или сюрреалистично, что в наши дни набор инструментов VS2015 принимает void main(). Действительно ?   -  person WhozCraig    schedule 01.09.2017
comment
В вашем последнем закрытом кейсе U не выводится - так что ваш кейс не скомпилируется. Чтобы сделать его выводимым, назовите его test.test2(a); и внутри теста 2 измените вперед‹T› на вперед‹X›   -  person Artemy Vysotsky    schedule 01.09.2017


Ответы (3)


Это отличный вопрос, который поначалу сбивает с толку почти всех.

template <class T>
class A
{
    template <class U>
    void foo(T&& t, U&& u);
};

В этом примере T не выводится (вы явно определяете его при создании экземпляра шаблона).

U выводится, потому что выводится из аргумента u.

Таким образом, почти во всех случаях это будет:

std::move(t);
std::forward<U>(u);
person Richard Hodges    schedule 01.09.2017
comment
Кстати, std::forward<T>(t); будет эквивалентно std::move(t); в этом случае (но менее явно). - person Jarod42; 01.09.2017

являются ссылками на пересылку T&& и U&&?

Нет, только U&& является ссылкой на пересылку, потому что U — это единственный выводимый аргумент шаблона. T уже был "выбран" при создании экземпляра A.

person Vittorio Romeo    schedule 01.09.2017

В дополнение к тому, что указали Ричард и Артемий, когда вы указали test.test2<A>( a ), тип X уже явно определен как A.

Когда вы измените его на test.test2( a ), тогда должен быть выведен тип X, и он должен скомпилироваться.

person Johanna Ye    schedule 03.04.2021