简体   繁体   English

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

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

I'm providing a const and non-const variation of a member function where I reuse the const version to implement the non-const version as described in this answer per Scott Meyers books. 我正在提供成员函数的const和非const变体,其中我重用const版本来实现非const版本, 如本答案中描述的每个Scott Meyers书籍。

The const version takes an argument of type: const版本采用类型的参数:

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

vs the non-const takes an argument of type: vs非const采用类型的参数:

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

In the implementation, I have to use reinterpret_cast because const_cast is not working. 在实现中,我必须使用reinterpret_cast因为const_cast不起作用。

Eg,: 例如,:

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

vs VS

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

Wouldn't this be in the spirit of what const_cast is meant for? 这不符合const_cast的意思吗? Is this just an oversight in the language definition to perhaps be fixed in C++2x or would const_cast never be in the spirit of things here? 这只是对语言定义的疏忽,或许可以在C ++ 2x中修复,或者const_cast永远不会符合这里的精神?

Here is more complete code: 这是更完整的代码:

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

Generally speaking, it's not safe to use const_cast to cast away const ness that appears in template arguments. 一般来说,使用const_cast来抛弃模板参数中出现的const是不安全的。 For example, consider this (admittedly, somewhat contrived) code: 例如,考虑这个(诚然,有些人为的)代码:

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

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

Here, a pointer to a Wrapper<const char *> points to a very different object than a Wrapper<char *> , so doing a const_cast to turn a Wrapper<const char *> * into a Wrapper<char *> * would result in a pointer to a struct containing an int now pointing at a struct containing a double , breaking some language rule whose name eludes me at the moment. 在这里,一个指向Wrapper<const char *>指向一个非常不同的对象比Wrapper<char *>所以做了const_cast把一个Wrapper<const char *> *Wrapper<char *> *将导致在一个指向struct的指针中,该struct包含一个int现在指向一个包含doublestruct ,打破了一些语言规则,其名称目前不在我身上。 :-) :-)

Since in general it's not safe to const_cast this way, the language spec doesn't allow for const_cast to be used like this, which is why in your case, even though the operation makes intuitive sense, the language disallows your code with const_cast . 因为一般来说const_cast这种方式不安全,语言规范不允许像这样使用const_cast ,这就是为什么在你的情况下,即使操作直观,语言也不允许使用const_cast代码。

I am fairly certain that using a reinterpret_cast here leads to undefined behavior, since the language considers std::function<T1> and std::function<T2> to be different, incompatible types when T1 and T2 aren't the same. 我相当肯定在这里使用reinterpret_cast会导致未定义的行为,因为语言认为std::function<T1>std::function<T2>是不同的,当T1T2不相同时,不兼容的类型。 It may happen to work on your system by pure coincidence, but I don't believe you can safely assume this will work. 它可能恰巧在您的系统上运行纯粹巧合,但我不相信您可以安全地认为这将起作用。

reinterpret_cast here is undefined behavior. reinterpret_cast这里是未定义的行为。 const_cast isn't appropriate, because the const ness of template parameters isn't something you can cast away. const_cast不合适,因为模板参数的const不是你可以抛弃的东西。

The easy way to solve this is, well, don't. 解决这个问题的简单方法是,不要这样做。 Get rid of some references. 摆脱一些参考。 Swap who implements it. 交换谁实现它。

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 stores things that are call-compatible with it. std::function存储与它调用兼容的东西。

If you take a Foo& , you can call a function expecting a Foo const& with it. 如果你选择Foo& ,你可以调用一个期望Foo const&它的Foo const& So you can store a std::function<void(Foo const&)> within a std::function<void(Foo&)> . 所以你可以在std::function<void(Foo const&)>存储一个std::function<void(Foo const&)> std::function<void(Foo&)>

Wrapping something in a std::function can involve allocating. std::function包装内容可能涉及分配。 So you may want to find a high-quality function_view<Sig> to replace your use of std::function . 因此,您可能希望找到一个高质量的function_view<Sig>来替换您对std::function

In another comment, you state that this code is in a critical loop. 在另一条评论中,您声明此代码处于关键循环中。 Eliminating std::function entirely is a good move, or at least reducing the type erasure taps and passing batches of data to it somehow. 完全消除std::function是一个很好的举动,或者至少减少类型擦除点击并以某种方式将批量数据传递给它。

The inversion of const/unconst is still appropriate; const / unest的反转仍然是合适的; we implement const in terms of mutable instead of mutable in terms of const because one is a covariant operation, the other is a contravariant operation. 我们用const表示const而不是const的变量,因为一个是协变运算,另一个是逆变运算。 See here . 看到这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM