Постоянные ссылки с typedef и шаблонами в С++

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

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

#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'

Ответы

Ответ 1

Это:

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
}

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

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();
}

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

Ответ 2

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

Я считаю крайне неудачным, что синтаксис С++ позволит:

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) на их справа, тогда вы сможете лечите a typedef как простую замену текста.

Ответ 3

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

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

Итак, error имеет тип int& not const int&.

Ответ 4

Чтобы поддерживать согласованность с правым левым правилом, я предпочитаю использовать такие квалификаторы '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>(); 

За дополнительной информацией обращайтесь this.

Ответ 5

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

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

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