能够使用static_cast抛弃constness为什么?

时间:2014-09-14 05:13:55

标签: c++

我们知道使用static_cast我们无法从表达式中删除constness。但是今天我遇到了一个可以做到这一点的场景。我无法弄清楚它是如何运作的。请在下面找到代码。此代码编译时没有任何错误,并给出正确的结果。

为什么这段代码没有出错?

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

3 个答案:

答案 0 :(得分:2)

关于void main(),它是a Microsoft-specific extension to the Visual C++ compiler

&static_cast<double>()位更令人费解。有趣的是,如果将double更改为int,则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++ Optimizing Compiler Version 18.00.21005.1 for x64
1>  Copyright (C) Microsoft Corporation.  All rights reserved.
1>  
1>  main.cpp
1>main.cpp: error C2101: '&' on constant
1>main.cpp: error C2664: 'void func1(int *)' : cannot convert argument 1 from 'int' to 'int *'
1>          Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

当我用intint main()替换double的所有实例(float除外),令人惊讶的是它会编译。完成intshortcharlong后,它会正确报告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

最后5个版本的unsigned版本也会产生C2101错误。我可以使用Visual C ++ 2013可靠地重现这一点。当Tfloatdouble时,似乎没有给出错误。 GCC对func0的所有调用产生编译错误:

main.cpp:14:18: error: lvalue required as unary '&' operand
         func1(&static_cast(ab));

这个问题让我想起a non-standard extension in 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警告(我总是使用&#34编译;将警告转为错误&#34;选项集):

1>  Microsoft (R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64
1>  Copyright (C) Microsoft Corporation.  All rights reserved.
1>
1>  main.cpp
1>main.cpp: error C2220: warning treated as error - no 'object' file generated
1>          main.cpp: see reference to function template instantiation 'void func0(void)' being compiled
1>main.cpp: warning C4238: nonstandard extension used : class rvalue used as lvalue

鉴于这些结果,这让我觉得这确实是一个编译器错误,甚至VS2013中的C ++编译器都表现出这种行为。它可能与C4238有关。作为T.C.在评论中提到,它也可能与浮点类型不能使用常量表达式这一事实有关。无论哪种方式,这都是我遇到过的更为奇怪的错误之一。

答案 1 :(得分:1)

你实际上并没有丢弃const,因为它是有效的而不是指针。你只是制作double的副本,它是原始的,是一个微不足道的副本。

答案 2 :(得分:0)

实际上,您的代码无法执行此操作....它无法编译。我收到此错误:

  

main.cpp:13:32:错误:左值作为一元&amp;操作数

可能你的编译器太宽容了。我尝试使用http://www.compileonline.com/compile_cpp_online.php

中的GNU GCC版本4.8.1

删除constness的方法是使用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;
}