为什么 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
来丢弃出现在模板参数中的const
ness 是不安全的。例如,考虑这个(诚然,有点做作的)代码:
template <typename T> struct Wrapper {
int x;
};
template <> struct Wrapper<char *> {
double y;
};
此处,指向 Wrapper<const char *>
的指针指向与 Wrapper<char *>
截然不同的对象,因此执行 const_cast
将 Wrapper<const char *> *
变为 Wrapper<char *> *
会导致指向包含 int
的 struct
现在指向包含 double
的 struct
的指针,打破了一些我现在不知道名字的语言规则. :-)
因为通常这样 const_cast
是不安全的,语言规范不允许这样使用 const_cast
,这就是为什么在你的情况下,即使操作很直观,该语言不允许您使用 const_cast
.
的代码
我相当确定在这里使用 reinterpret_cast
会导致未定义的行为,因为当 T1
时语言认为 std::function<T1>
和 std::function<T2>
是不同的、不兼容的类型和 T2
不一样。它可能碰巧在你的系统上工作纯属巧合,但我不相信你可以安全地假设它会工作。
reinterpret_cast
这里是未定义的行为。 const_cast
不合适,因为模板参数的 const
ness 不是您可以丢弃的东西。
解决这个问题的简单方法是,不要这样做。摆脱一些参考。交换实施者。
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.
我提供了成员函数的 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
来丢弃出现在模板参数中的const
ness 是不安全的。例如,考虑这个(诚然,有点做作的)代码:
template <typename T> struct Wrapper {
int x;
};
template <> struct Wrapper<char *> {
double y;
};
此处,指向 Wrapper<const char *>
的指针指向与 Wrapper<char *>
截然不同的对象,因此执行 const_cast
将 Wrapper<const char *> *
变为 Wrapper<char *> *
会导致指向包含 int
的 struct
现在指向包含 double
的 struct
的指针,打破了一些我现在不知道名字的语言规则. :-)
因为通常这样 const_cast
是不安全的,语言规范不允许这样使用 const_cast
,这就是为什么在你的情况下,即使操作很直观,该语言不允许您使用 const_cast
.
我相当确定在这里使用 reinterpret_cast
会导致未定义的行为,因为当 T1
时语言认为 std::function<T1>
和 std::function<T2>
是不同的、不兼容的类型和 T2
不一样。它可能碰巧在你的系统上工作纯属巧合,但我不相信你可以安全地假设它会工作。
reinterpret_cast
这里是未定义的行为。 const_cast
不合适,因为模板参数的 const
ness 不是您可以丢弃的东西。
解决这个问题的简单方法是,不要这样做。摆脱一些参考。交换实施者。
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.