const和非const函数 [英] Const and non-const functors

查看:155
本文介绍了const和非const函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这似乎应该经常被问到和回答,但我的搜索fu已经失败了我。



我正在写一个函数,我想接受某种类型的通用可调用对象(包括裸函数,手动函数对象, bind std :: function

函数目前声明如下:

 模板< typename T,typename F> 
size_t do_something(const T& a,const F& f)
{
T internal_value(a);
//做一些复杂的事情
// loop {
// loop {
f(static_cast< const T&>(internal_value),other_stuff);
//做一些事情
//}
//}
return 42;
}



我通过引用接受函子,因为我想保证它不会被复制到函数的入口,因此实际调用对象的同一个实例。它是一个const引用,因为这是接受临时对象的唯一方法(当使用手动函数或 bind 时很常见)。



但是这要求函子实现 operator()为const。我不想要;我想要它能够接受两个。



我知道我可以声明这个方法的两个副本,一个接受它作为const和一个作为非const,命令以涵盖这两种情况。但我不想这样做,因为评论是隐藏了很多的代码,我不想复制(包括一些循环结构,所以我不能提取到一个辅助方法,而不只是移动的问题) 。



我也知道我可以欺骗和 const_cast 函数到非const在调用它之前,但这感觉有潜在的危险(特别是如果函子有意地实现const和非const调用操作符时会调用错误的方法)。



我考虑接受函子作为 std :: function / boost :: function ,但是这感觉像一个重的解决方案,应该是一个简单的问题。 (特别是在函子不应该做任何事情的情况下)



有没有一个正确的方式来满足这些要求, >

[注意:我喜欢一个不需要C ++ 11的解决方案,虽然我对C ++ 11的答案也感兴趣,因为我在项目中使用类似的结构]

解决方案

您是否尝试过转发层,强制推断限定符?让编译器通过正常的模板实例化机制执行算法复制。

  template< typename T ,类型名F> 
size_t do_something_impl(const T& a,F& f)
{
T internal_value(a);
const T& c_iv = interval_value;
//做一些复杂的事情
// loop {
// loop {
f(c_iv,other_stuff);
//做一些事情
//}
//}
return 42;
}

template< typename T,typename F>
size_t do_something(const T& a,F& f)
{
return do_something_impl< T,F
}

template< typename T,typename F>
size_t do_something(const T& a,const F& f)
{
return do_something_impl< T,const F>(a,f)
}

示范: http://ideone.com/owj6oB



包装器应完全内联,完全没有运行时成本,除非因为你可能会得到更多的模板实例化(因此更大的代码大小),虽然只会发生在类型没有 operator()()const where const(或临时)和非const函数都得到传递。


This seems like something that ought to be frequently asked and answered, but my search-fu has failed me.

I'm writing a function which I want to accept a generic callable object of some kind (including bare function, hand-rolled functor object, bind, or std::function) and then invoke it within the depths of an algorithm (ie. a lambda).

The function is currently declared like this:

template<typename T, typename F>
size_t do_something(const T& a, const 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;
}

I'm accepting the functor by reference because I want to guarantee that it does not get copied on entry to the function, and thus the same instance of the object is actually called. And it's a const reference because this is the only way to accept temporary objects (which are common when using hand-rolled functors or bind).

But this requires that the functor implement operator() as const. I don't want to require that; I want it to be able to accept both.

I know I can declare two copies of this method, one that accepts it as const and one as non-const, in order to cover both cases. But I don't want to do that as the comments are hiding quite a lot of code that I don't want to duplicate (including some loop constructs, so I can't extract them to a secondary method without just moving the problem).

I also know I could probably cheat and const_cast the functor to non-const before I invoke it, but this feels potentially dangerous (and in particular would invoke the wrong method if the functor intentionally implements both const and non-const call operators).

I've considered accepting the functor as a std::function/boost::function, but this feels like a heavy solution to what ought to be a simple problem. (Especially in the case where the functor is supposed to do nothing.)

Is there a "right" way to satisfy these requirements short of duplicating the algorithm?

[Note: I would prefer a solution that does not require C++11, although I am interested in C++11 answers too, as I'm using similar constructs in projects for both languages.]

解决方案

Have you tried a forwarding layer, to force inference of the qualifier? Let the compiler do the algorithm duplication, through the normal template instantiation mechanism.

template<typename T, typename F>
size_t do_something_impl(const T& a, F& f)
{
   T internal_value(a);
   const T& c_iv = interval_value;
   // do some complicated things
   // loop {
   //   loop {
       f(c_iv, other_stuff);
       // do some more things
   //   }
   // }
   return 42;
}

template<typename T, typename F>
size_t do_something(const T& a, F& f)
{
   return do_something_impl<T,F>(a, f);
}

template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
   return do_something_impl<T,const F>(a, f);
}

Demo: http://ideone.com/owj6oB

The wrapper should be completely inlined and have no runtime cost at all, except for the fact that you might end up with more template instantiations (and therefore larger code size), though that will only happen when for types with no operator()() const where both const (or temporary) and non-const functors get passed.

这篇关于const和非const函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆