回答新的放宽要求。
在对另一个答案的评论中,OP 已将要求澄清/更改为……
“我可以要求如果函子作为临时传入,那么它必须有一个 operator() const。我只是不想将其限制于此,这样如果函子没有作为临时传入(当然也不是 const 非临时),那么它允许有一个非常量 operator() ,这将被称为“
那么这根本不是问题:只需提供一个接受临时的重载。
有几种方法可以区分原始的基本实现,例如在 C++11 中一个额外的默认模板参数,在 C++03 中一个额外的默认普通函数参数。
但最清楚的是恕我直言,只是给它一个不同的名称,然后提供一个重载的包装器:
template<typename T, typename F>
size_t do_something_impl( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something( T const& a, F const& f)
{ return do_something_impl( a, f ); }
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{ return do_something_impl( a, f ); }
注意:不需要do_something_impl
显式指定实例化,因为它是从左值参数推断出来的。
这种方法的主要特点是它支持更简单的调用,代价是当它有非时不支持临时作为参数const
operator()
。
原答案:
您的主要目标是避免仿函数的复制,并接受一个临时参数作为实际参数。
在 C++11 中,您可以只使用右值引用,&&
对于 C++03,问题是一个临时仿函数实例作为实际参数,其中该仿函数具有非const
operator()
.
一种解决方案是将负担转嫁给客户端代码程序员,例如
例子:
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
enum With_temp { with_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_temp, F const& f )
{
return do_something( a, const_cast<F&>( f ) );
}
如果希望直接支持临时const
类型,以便在这种罕见的情况下也简化客户端代码程序员的生活,那么一个解决方案就是添加一个额外的重载:
enum With_const_temp { with_const_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_const_temp, F const& f )
{
return do_something( a, f );
}
感谢 Steve Jessop 和 Ben Voigt 对此案的讨论。
另一种更通用的 C++03 方法是提供以下两个小功能:
template< class Type >
Type const& ref( Type const& v ) { return v; }
template< class Type >
Type& non_const_ref( Type const& v ) { return const_cast<T&>( v ); }
然后do_something
,正如上面在这个答案中给出的,可以被称为......
do_something( a, ref( MyFunctor() ) );
do_something( a, non_const_ref( MyFunctor() ) );
为什么我没有立即想到这一点,尽管我已经将这个解决方案用于字符串构建等其他事情:创建复杂性很容易,但更难简化!:)