Мы знаем, что используя static_cast, мы не можем удалить константу из выражения. Но сегодня я столкнулся с одним сценарием, где я могу это сделать. Я не могу понять, как это на самом деле работает. Пожалуйста, найдите ниже код. Этот код компилируется без ошибок и дает правильный результат.
почему этот код не дает никакой ошибки?
void func1(double *ptr)
{
cout<<*ptr;
}
void main()
{
const double ab=2;
func1(&static_cast<double>(ab));//I put & operator infront of static_cast and this works.
cin.get();
}
Что касается void main()
, это специфичное для Microsoft расширение компилятора Visual C ++.
&static_cast<double>()
немного более загадочно. Интересно, если вы поменяете double
в int
s, компилятор Visual C ++ (2013) правильно сообщает об ошибке:
#include <iostream>
void func1(int* ptr)
{
std::cout << *ptr;
}
int main()
{
const int ab = 2;
func1(&static_cast<int>(ab));
std::cin.get();
}
Приведенный фрагмент кода дает:
1> Оптимизатор компиляции Microsoft (R) C / C ++ версии 18.00.21005.1 для x64 1> Авторские права (C) Microsoft Corporation. Все права защищены. 1> 1> main.cpp 1> main.cpp: ошибка C2101: '' на константе 1> main.cpp: ошибка C2664: «void func1 (int *)»: невозможно преобразовать аргумент 1 из «int» в «int *» 1> Преобразование из целочисленного типа в тип указателя требует reinterpret_cast, приведения в стиле C или приведения в функциональном стиле
Когда я заменяю все экземпляры int
(кроме int main()
) с double
или же float
, как ни удивительно, он компилируется. Когда сделано с int
, short
, char
, или же long
Правильно сообщает C2101.
Просто для дальнейшего изучения я преобразовал ваши функции в шаблоны:
#include <iostream>
template<typename T>
void func1(T* ptr)
{
std::cout << *ptr;
}
template<typename T>
void func0()
{
const T ab = 2;
func1<T>(&static_cast<T>(ab));
}
И попытался позвонить следующее:
func0<float>(); // No error
func0<double>(); // No error
func0<char>(); // C2101
func0<int>(); // C2101
func0<short>(); // C2101
func0<long>(); // C2101
func0<long long>(); // C2101
unsigned
Версии последних 5 также выдают ошибки C2101. Я могу надежно воспроизвести это с Visual C ++ 2013. Кажется, что ошибка не появляется, когда T
это float
или double
, GCC выдает ошибки компиляции при всех вызовах func0
с:
main.cpp: 14: 18: ошибка: lvalue требуется как унарный операнд func1 (static_cast (аb));
Эта проблема напоминает мне о нестандартное расширение в Visual C ++ это позволяет вам взять адрес класса временным. Итак, я попробовал это с типом класса:
struct Foo
{
Foo(int) {} // Foo(double) {} does not change the outcome
};
std::ostream& operator<<(std::ostream& os, const Foo&)
{
return os;
}
При звонке func0<Foo>()
, Я получаю ожидаемое предупреждение C4238 (я всегда компилирую с установленным параметром «Превратить предупреждения в ошибки»):
1> Оптимизатор компиляции Microsoft (R) C / C ++ версии 18.00.21005.1 для x64 1> Авторские права (C) Microsoft Corporation. Все права защищены. 1> 1> main.cpp 1> main.cpp: ошибка C2220: предупреждение рассматривается как ошибка - файл объекта не создан 1> main.cpp: см. Ссылку на экземпляр шаблона функции 'void func0 (void)', который компилируется 1> main.cpp: предупреждение C4238: используется нестандартное расширение: в качестве lvalue используется класс rvalue
Учитывая эти результаты, это заставляет меня думать, что это действительно ошибка компилятора, и даже компилятор C ++ в VS2013 демонстрирует такое поведение. Это может быть связано с C4238. Как Т.С. Как уже упоминалось в комментариях, это также может быть связано с тем фактом, что типы с плавающей запятой не могут использоваться константные выражения. В любом случае, это одна из самых странных ошибок, с которыми я сталкивался.
Вы на самом деле не отбрасываете const
, так как это действительный, а не указатель. Вы только делаете копию double
, который, будучи примитивным, является тривиальной копией.
На самом деле, ваш код не может этого сделать …. он не компилируется. Я получаю эту ошибку:
main.cpp: 13: 32: ошибка: lvalue требуется как унарный & операнд
Возможно, ваш компилятор слишком разрешительный. Я пытался с GNU GCC версии 4.8.1 от http://www.compileonline.com/compile_cpp_online.php
Может ли способ удаления констант использовать const_cast
(даже если это не рекомендуется сделать это …)
void func1(double *ptr)
{
cout<<*ptr;
}
int main()
{
const double ab=2;
const double* ptr = &ab;
func1(const_cast<double*>(ptr));
return 0;
}