Защо const lvalues ​​се обвързват по различен начин от const rvalues ​​при дадени T&& и const T& претоварвания?

За този код (достъпен на http://ideone.com/Mo7fQr)

template<typename T>
void f(const T&) { std::cout << "const T& overload\n"; }

template<typename T>
void f(T&&) { std::cout << "T&& overload\n"; }

int main()
{
  const int x = 0;

  f(x);                 // calls const T& overload
  f(std::move(x));      // calls T&& overload
}

първото извикване на f (с lvalue) извиква const T& претоварване, докато второто извикване (с rvalue) извиква T&& претоварване. Поне това се случва с gcc 4.8.1 и най-новия VC++ (VC12).

Мисля, че разбирам защо второто извикване се разрешава така: тъй като първият шаблон инстанцира вземане на параметър const int&, докато вторият шаблон инстанцира вземане на параметър const int&& и тъй като аргументът, подаден на сайта за извикване, е rvalue, той преференциално се свързва с препратката към rvalue. (Вярвам, че това е посочено в стандарта C++11 в 13.3.3.2/3 bullet 1 sub-bullet 4.)

Но за първото извикване на f и двата шаблона инстанцират приемането на параметър от тип const int&. Така че защо първият шаблон е предпочитан, когато се подава const lvalue?


person KnowItAllWannabe    schedule 20.07.2013    source източник


Отговори (1)


Когато една и съща специализация на шаблон на функция може да бъде генерирана от повече от една декларация, декларациите се разграничават чрез частично подреждане на шаблони на функции, както е описано в стандарта C++11 §14.5.6.2 Частично подреждане на шаблони на функции [temp.func.order]. Компилаторът определя кой от шаблоните е най-специализиран и го предпочита.

Във вашия пример претоварването const T& на f е по-специализирано от претоварването T&&. Интуитивно T&& може да бъде изведено до всичко, което const T& може, но не и обратното, така че const T& е по-специфично и следователно претоварването му с функции е по-специализирано.

person Casey    schedule 20.07.2013
comment
Как може T const& да не съвпада с нищо, което T&& може? Имате ли пример? (Мисля, че всъщност може да съвпада с всичко, но ще изисква квалификационна корекция за някои неща, като неконстантни lvalues ​​и rvalues. Също така, за rvalues ​​T&& се предпочита пред T const&, така че това е.) - person Xeo; 20.07.2013
comment
@Xeo, например, T const& не може да изведе int& или int&&. Ако сте се опитали да извикате f с параметър int&, претоварването f(const T&) е специализирано за f(const int&) - особено не f(int&) - и изисква последователност за преобразуване int& -› const int&. - person Casey; 20.07.2013
comment
Замених съвпадение с be deduced to в отговора, мисля, че е малко по-ясно. - person Casey; 20.07.2013