为什么 const_cast 不能处理 std::function 的参数?

Why doesn't const_cast work on arguments to std::function?

我提供了成员函数的 const 和非常量变体,其中我重用 const 版本来实现非常量版本,如 described in this answer 根据 Scott Meyers 的书籍。

const 版本采用以下类型的参数:

const std::function< void (const Foo &) > &

vs 非常量采用类型参数:

const std::function< void (      Foo &) > &

在实现中,我必须使用 reinterpret_cast 因为 const_cast 不起作用。

例如:

const std::function< void (Foo &) > & Processor;
reinterpret_cast< const std::function< void (const Foo &) > & >( Processor );

const std::function< void (Foo &) > & Processor;
const_cast< const std::function< void (const Foo &) > & >( Processor );

这不符合 const_cast 的精神吗?这只是语言定义中的疏忽,可能会在 C++2x 中修复,还是 const_cast 永远不会符合这里的精神?

这里是更完整的代码:

void Collection::ProcessCollection(const std::function< void (const Foo &) > & Processor) const
{
    for( int idx = -1 ; ++idx < m_LocalLimit ; )
    {
        if ( m_Data[ idx ] )
        {
            Processor( m_Data[idx] );
        }
    }

    const int overflowSize = OverflowSize();

    for( int idx = -1 ; ++idx < overflowSize ; )
    {
        Processor( (*m_Overflow)[ idx ] );
    }
}

void Collection::ProcessCollection(const std::function< void (Foo &) > & Processor)
{
    const Collection * constThis = const_cast< const Collection * >( this );
    const std::function< void (const Foo &) > & constProcessor
        = reinterpret_cast< const std::function< void (const Foo &) > & >( Processor );

    constThis->ProcessCollection( constProcessor );
}

一般来说,使用const_cast 来丢弃出现在模板参数中的constness 是不安全的。例如,考虑这个(诚然,有点做作的)代码:

template <typename T> struct Wrapper {
    int x;
};

template <> struct Wrapper<char *> {
    double y;
};

此处,指向 Wrapper<const char *> 的指针指向与 Wrapper<char *> 截然不同的对象,因此执行 const_castWrapper<const char *> * 变为 Wrapper<char *> * 会导致指向包含 intstruct 现在指向包含 doublestruct 的指针,打破了一些我现在不知道名字的语言规则. :-)

因为通常这样 const_cast 是不安全的,语言规范不允许这样使用 const_cast,这就是为什么在你的情况下,即使操作很直观,该语言不允许您使用 const_cast.

的代码

我相当确定在这里使用 reinterpret_cast 会导致未定义的行为,因为当 T1 时语言认为 std::function<T1>std::function<T2> 是不同的、不兼容的类型和 T2 不一样。它可能碰巧在你的系统上工作纯属巧合,但我不相信你可以安全地假设它会工作。

reinterpret_cast 这里是未定义的行为。 const_cast 不合适,因为模板参数的 constness 不是您可以丢弃的东西。

解决这个问题的简单方法是,不要这样做。摆脱一些参考。交换实施者。

void Collection::ProcessCollection(std::function< void (const Foo &) > Processor) const
{
  Collection * mutableThis = const_cast< Collection * >( this );

  mutableThis->ProcessCollection( Processor );
}

void Collection::ProcessCollection(std::function< void (Foo &) > Processor)
{
  for( int idx = -1 ; ++idx < m_LocalLimit ; )
  {
    if ( m_Data[ idx ] )
    {
      Processor( m_Data[idx] );
    }
  }

  const int overflowSize = OverflowSize();

  for( int idx = -1 ; ++idx < overflowSize ; )
  {
    Processor( (*m_Overflow)[ idx ] );
  }
}

std::function 存储 call-compatible 的内容。

如果你使用 Foo&,你可以用它调用一个需要 Foo const& 的函数。所以你可以在 std::function<void(Foo&)>.

中存储 std::function<void(Foo const&)>

将某些东西包装在 std::function 中可能涉及分配。所以你可能想找一个 high-quality function_view<Sig> 来代替你对 std::function.

的使用

在另一条评论中,您声明此代码处于关键循环中。完全消除 std::function 是一个很好的举措,或者至少减少类型擦除抽头并以某种方式将数据批量传递给它。

倒转const/unconst还是合适的;我们用 mutable 来实现 const,而不是用 const 来实现 mutable,因为一个是协变操作,另一个是逆变操作。 See here.