我正在提供成员函数的const和非const变体,其中我重用const版本以按照Scott Meyers的书中的described in this answer来实现非const版本。
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 );
vs
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 );
}
答案 0 :(得分:4)
通常来说,使用const_cast
来抛弃模板参数中出现的const
并不安全。例如,考虑以下代码(当然,有些人为设计):
template <typename T> struct Wrapper {
int x;
};
template <> struct Wrapper<char *> {
double y;
};
在这里,指向Wrapper<const char *>
的指针指向的对象与Wrapper<char *>
完全不同,因此执行const_cast
将Wrapper<const char *> *
变成{{1} }会导致指向包含Wrapper<char *> *
的{{1}}的指针,现在指向包含struct
的{{1}}的指针,这打破了目前我不知道的语言规则。 :-)
通常,以这种方式int
是不安全的,因此语言规范不允许struct
像这样使用,这就是您的情况,即使操作变得直观在某种意义上说,该语言不允许您使用double
编写代码。
我相当确定,在此处使用const_cast
会导致未定义的行为,因为当const_cast
和{时,语言会认为const_cast
和reinterpret_cast
是不同的,不兼容的类型{1}}不同。碰巧,它可能恰好在您的系统上工作,但是我不相信您可以放心地认为这会起作用。
答案 1 :(得分:1)
reinterpret_cast
是未定义的行为。 const_cast
是不合适的,因为模板参数的const
性质是您无法抛弃的。
解决这个问题的简单方法是,不要。摆脱一些参考。交换实施它的人。
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
存储与呼叫兼容的内容。
如果您使用Foo&
,则可以调用包含Foo const&
的函数。因此,您可以将std::function<void(Foo const&)>
存储在std::function<void(Foo&)>
中。
在std::function
中包装内容可能涉及分配。因此,您可能希望找到高质量的function_view<Sig>
来代替对std::function
的使用。
在另一条评论中,您声明该代码处于关键循环中。完全消除std::function
是一个好方法,或者至少减少类型擦除抽头并以某种方式将大量数据传递给它。
const / unconst的反转仍然合适;我们以可变的方式实现const而不是以const的方式实现const,因为一个是协变运算,另一个是协变运算。 See here。