2016-11-11 14 views
0

Может кто-то помочь мне понять, почему выход следующего кодаТип вычет при использовании универсальных ссылки

template< typename T > 
void check() 
{ 
    std::cout << "unknow type" << std::endl; 
} 

template<> 
void check<int>() 
{ 
    std::cout << "int" << std::endl; 
} 

template<> 
void check<int&>() 
{ 
    std::cout << "int&" << std::endl; 
} 

template<> 
void check<int&&>() 
{ 
    std::cout << "int&&" << std::endl; 
} 

template< typename T > 
void bar(T&& a) 
{ 
    check<T>(); 
} 

int main() 
{ 
    bar(0); 

    int a = 0; 
    bar(a); 
} 

является

int 
int& 

и не

int&& 
int& 

С моей точки view, кажется более интуитивным, что ссылка r-value остается в качестве ссылки на r-значение и ссылкой l-value lv alue reference. Однако кажется, что только ссылки l-value остаются в качестве ссылок на l-значение, а значения r становятся неосновными. Какова мотивация/идея этого?

+5

Вы используете 'check ', а не 'check '; Почему вы ожидаете, что' && 'будет там, когда вы явно опустите его? – ildjarn

+0

Я ожидал, что 'bar (0)' будет таким же, как 'bar (0)'. При замене в моем коде выше 'bar (0)' на 'bar (0)', тогда вывод фактически является 'int && \ n int &'. –

+3

Тип 'bar ' is 'void (T &&)', тип 'bar ' is 'void (T && &&)' (перед свертыванием ссылки). – Oktalist

ответ

4

bar(0); вызывает специализацию bar<int>(int&&) т.е. T выводится в int, так check<T>() является check<int>(). Тип параметра - T&&, который равен int&&, но это тип параметра, а не тип T.

Это полностью соответствует рекомендациям, не связанным с пересылкой. Если вы определяете:

template<typename T> void baz(T&); 

и вы называете его с Lvalue типа int затем T выводится в int, не int&

Единственное, что особенного ссылки экспедиторских как ваш пример использует то, что для T&& тип можно вывести как ссылку на lvalue, назовите его R, и в этом случае тип параметра - R&&, который совпадает с add_rvalue_reference_t<R>, который равен R. Таким образом, для вызова bar(a) вы звоните специализации bar<int&>(int&) т.е. T выводятся в int&

При вызове bar<int&&>(0) с явным шаблоном списка аргументов нет вывода аргумента, и поэтому T замещен int&&, поэтому типа параметра T&& является add_rvalue_reference_t<int&&>, который является только int&&.