Константные ссылки с typedef и шаблонами в C++

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

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

#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 ответов

Это:

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

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

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

Я считаю крайне прискорбным, что синтаксис 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 как простая замена текста.

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

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

Так error имеет тип int& не const int&,

Для обеспечения соответствия правилу " Правое левое", я предпочитаю использовать квалификаторы "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>(); 

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

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

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

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

Другие вопросы по тегам