Константные ссылки с 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 не может быть применен позже.