Проблема по ссылочной переменной параметра шаблона - PullRequest
4 голосов
/ 22 августа 2010

В следующем небольшом примере показана моя проблема:

template<class T> struct X
{
    static void xxx(T& x) { }
    static void xxx(T&& x) { }
};

int main(int argc, char** argv)
{
    int x = 9;
    X<int>::xxx(x); // OK.
    X<int&>::xxx(x); // ERROR!
    return 0;
}

Сообщение об ошибке (GCC):

error: 'static void X :: xxx (T &&) [with T= int &] 'не может быть перегружено
ошибка: с' static void X :: xxx (T &) [с T = int &] '

Почему?T = int& ---> Заменено T& на int&& в static void xxx(T& x)?

Если ответ на вопрос положительный, то:

  • T&не является lvalue-ссылкой и становится rvalue-ссылкой!
  • И следующий код должен работать:

Но это не так:

template<class T> struct X
{
    static void xxx(T& x) { }
};

int main(int argc, char** argv)
{
    X<int&>::xxx(2); // ERROR!
    return 0;
}

Сообщение об ошибке (GCC):

ошибка: нет соответствующей функции для вызова 'X :: xxx (int)'
примечание: кандидаты: static void X :: xxx (T &)[с T = int &]

Тогда T& с T = int& не равно T&& и не является ссылкой-значением.но если это не так, почему первый пример не работает?(это рекурсивная проблема!)


Но подобная проблема не возникала для типов указателей:

#include <iostream>

template<class T> struct X
{
    static void xxx(T* x) { std::cout << **x << std::endl; }
};

int main(int argc, char** argv)
{
    int x = 10;
    int* xx = &x;
    X<int*>::xxx(&xx); // OK. call X<int*>::xxx(int**)
    return 0;
}

Почему ссылки отличаются в этом поведении?

1 Ответ

10 голосов
/ 22 августа 2010

Стандарт языка C ++ 11 содержит объяснение того, как это работает в §8.3.2 [dcl.ref] / 6 (переформатирован для удобства чтения):

Если typedef, тип шаблон-параметра или decltype-specier обозначает тип TR, который является ссылкой на тип T,

  • попыткасоздать тип "lvalue ссылка на cv TR" создает тип "lvalue ссылка на T"
  • попытка создать тип "rvalue ссылка на cv TR "создает тип TR.

Давайте рассмотрим ваш пример (я переименовал ваш T в TR, чтобы он соответствовал языку выше):

template<class TR> struct X
{
    static void xxx(TR& x)  { }
    static void xxx(TR&& x) { }
};

Если мы попытаемся создать экземпляр X с TR = int& (то есть T = int), экземпляры xxx будут выглядеть следующим образом:

static void xxx(TR& x)  { }   -->   static void xxx(int& x) { }
static void xxx(TR&& x) { }   -->   static void xxx(int& x) { }

ВВ первом случае мы пытаемся создать «ссылку lvalue на TR», которая становится «ссылкой lvalue на T».T равно int, поэтому тип параметра становится int&.

Во втором случае мы пытаемся создать «ссылку на значение r * для TR», которая становится TR, то естьint&.

Тип параметра одинаков для обеих перегрузок, поэтому возникает ошибка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...