【问题标题】:Does clang think I need to point to a "const function"?clang 是否认为我需要指向“const 函数”?
【发布时间】:2020-11-07 16:29:49
【问题描述】:

GodBolt

考虑以下代码sn-p:

using A = void(*)(int);

A foo(const void* ptr) 
{
    return reinterpret_cast<A>(ptr);
}

GCC 10 非常喜欢这个。但是,clang++-10 说这是一个错误!

<source>:5:12: error: reinterpret_cast from 'const void *' to 'A' (aka 'void
 (*)(int)') casts away qualifiers

    return reinterpret_cast<A>(ptr);

           ^~~~~~~~~~~~~~~~~~~~~~~~

函数在 C++(和 C)中是不可变的,并且没有“const 函数”。那么为什么clang++在这里抱怨呢?

【问题讨论】:

  • @OutOfBound:偷偷摸摸! ......但是 - 它不起作用。在 GodBolt 链接上执行此操作,您会看到函数返回类型必须更改。
  • 因为你不能用 reinterpret_cast 抛弃 const 限定符。没关系,函数指针是不可变的。
  • 关于将函数指针转换为数据指针,反之亦然,难道没有一些重要的警告吗? (常规函数指针,而不是完全不同的成员函数指针。)
  • AFAIK 将函数指针转换为 void* 是非法的,这样会使 clang 正确。
  • @NathanOliver:如果是void*,clang 不会抱怨。

标签: c++ function-pointers clang++ reinterpret-cast const-correctness


【解决方案1】:

因为标准是这样说的。

[expr.reinterpret.cast]/2:

reinterpret_­cast 运算符不应抛弃常量。

[expr.const.cast]/7:

T1 类型到T2 类型的转换抛弃常量 如果T1T2 不同,则T1 的cv-decomposition 产生n这样T2 的 cv 分解形式为

并且没有将T1 转换为

这里T1是const void*,T2是void (*)(int),n = 1,T2的cv-decomposition有cv0 = "", P0 = "pointer to", cv1 = "", U2 = @987654336 @,所以T1对应的版本是void*。没有从const void*void* 的资格转换。由此可见,转换抛弃了 constness,reinterpret_cast 无法执行。

【讨论】:

  • 您假设 T2 可以是函数类型并且定义仍然可以成立。但这没有意义,因为 const 的全部意义在于保证不会通过指针写入,而“抛弃 constness”就是抛弃这种保证。对标准的反常识解释——好吧,它们没有意义。但是 +1 用于解释 clang 似乎在做什么。
【解决方案2】:

警告这不是生产友好的代码!

using A = void(*)(int);

A foo(const void* ptr)
{
    union McGayver {
         const void* ptr;
         A a;
    } u;
    u.ptr = ptr;
    return u.a;
}

https://godbolt.org/z/1e1oE6

【讨论】:

  • 商定的、未定义的行为和不可优化的代码永远不会对生产友好。
猜你喜欢
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 2021-05-25
  • 2017-07-15
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
相关资源
最近更新 更多