константные ссылки с typedef и шаблонами в c ++ - PullRequest
15 голосов
/ 27 сентября 2010

Я слышал, что временные объекты могут быть назначены только постоянным ссылкам.

Но этот код выдает ошибку

#include <iostream.h>    
template<class t>
t const& check(){
  return t(); //return a temporary object
}    
int main(int argc, char** argv){

const int &resCheck = check<int>(); /* fine */
typedef int& ref;
const ref error = check<int>(); / *error */
return 0;
}

Получаемая ошибка: invalid initialization of reference of type 'int&' from expression of type 'const int'

Ответы [ 5 ]

20 голосов
/ 27 сентября 2010

Это:

typedef int& ref;
const ref error;

Не делает то, что вы думаете, что делает. Рассмотрим вместо этого:

typedef int* pointer;
typedef const pointer const_pointer;

Тип const_pointer является int* const, , а не const int *. То есть, когда вы говорите const T, вы говорите «создайте тип, в котором T неизменен»; поэтому в предыдущем примере указатель (не указатель) становится неизменным.

Ссылки не могут быть сделаны const или volatile. Это:

int& const x;

не имеет смысла, поэтому добавление cv-квалификаторов к ссылкам не имеет никакого эффекта.

Следовательно, error имеет тип int&. Вы не можете присвоить ему const int&.


В вашем коде есть другие проблемы. Например, это, безусловно, неправильно:

template<class t>
t const& check()
{
    return t(); //return a temporary object
}

То, что вы здесь делаете, возвращает ссылку на временный объект , срок действия которого заканчивается, когда функция возвращает . То есть, вы получите неопределенное поведение, если будете его использовать, потому что в рефранде нет объекта. Это не лучше чем:

template<class t>
t const& check()
{
    T x = T();
    return x; // return a local...bang you're dead
}    

Лучшим тестом будет:

template<class T>
T check()
{
    return T();
}

Возвращаемое значение функции является временным, поэтому вы все еще можете проверить, что вы действительно можете привязать временные ссылки к константным ссылкам.

8 голосов
/ 27 сентября 2010

Это очень распространенная ошибка для англоговорящих людей из-за того, как работает английская грамматика.

Я считаю крайне прискорбным, что синтаксис C ++ допускает и то и другое:

const int // immutable int
int const // immutable int

иметь то же значение.

Это не облегчает, на самом деле, и не является составным, так как:

const int* // mutable pointer to immutable int
int* const // immutable pointer to mutable int

, конечно, НЕ имеет того же значения.

И это, к сожалению для вас, то, что здесь происходит, как объясняет @GMan.

Если вы хотите избежать ошибок такого рода в будущем, возьмите в привычку квалифицировать ваши типы (const иvolatile) на справа , тогда вы сможете трактовать typedef как простую замену текста.

7 голосов
/ 27 сентября 2010

Ваш код выдает ошибку, потому что квалификатор const в const ref error просто игнорируется, потому что 8.3.2/1 говорит

Cv-квалифицированные ссылки некорректны, за исключением случаев, когда cv-квалификаторы вводятся с помощью typedef (7.1.3) или аргумента типа шаблона (14.3), и в этом случае cv-квалификаторы игнорируются .`

То есть error имеет тип int&, а не const int&.

3 голосов
/ 27 сентября 2010

Чтобы сохранить соответствие правилу Right Left , я предпочитаю использовать квалификаторы 'cv' вот так.

int const x = 2; // x is a const int (by applying Right Left rule)

int const *p = &x;  // p is a pinter to const int

В вашем примере я бы написал const ref error = check<int>(); вот так

ref const error = check<int>(); // parsed as error is a const reference to an integer

Как указал @Prasoon Saurav, квалификаторы cv игнорируются при вводе через typedef, потому что, как говорит @GMan, ссылки, квалифицированные cv, не сформированы.

Следовательно, объявление, как показано ниже, является ошибкой.

   int &error = check<int>(); 

Проверьте это для получения дополнительной информации.

0 голосов
/ 27 сентября 2010

Это скомпилировано:

typedef const int& ref; 
ref error = check<int>(); 

Компилятор VC ++ дает некоторые объяснения вашей ошибки: квалификатор применяется к ссылочному типу; игнорируются. Тип ссылки должен быть объявлен как константа, const не может быть применен позже.

...