FireEmissary

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  14 随笔 :: 0 文章 :: 20 评论 :: 0 Trackbacks

#

我正设计一个布局类,对于托管的对象自动计算更新后的布局位置后调用用户的回调函数.bind用得非常high,然后最后却编译不过.
抽象出来就是如下代码:
#include <iostream>
#include 
<boost/bind.hpp>
#include 
<boost/function.hpp>
class test1
{
public:
    template
<typename S>
    
double handle(S s)
    {
        s(
1);
        std::cout
<<"test1\n";
        
return 1;
    }
    template
<typename F>
    
void handle1(F f)    {
boost::bind(
&test1::handle<F>,this,f)();//这里
    }

};
class test2
{
public:
    
double handle(int i)
    {
        std::cout
<<"test2\n";
        
return i;
    }
};
int _tmain(int argc, _TCHAR* argv[])
{
    test2 t2;
    test1 t1;

    t1.handle1(boost::bind(
&test2::handle,t2,_1));
    
return 0;
}
原来,bind为了支持
boost::bind(  std::logical_and<bool>(),     boost::bind(std::greater<int>(),_1,5),   boost::bind(std::less_equal<int>(),_1,10));
这类操作,内部自动对bind_t(即bind的返回类型)调用取得结果来作参数.代价就是不能把bind_t作为参数了.解决方法是,boost::ref包起来
boost::bind(&test1::handle<F>,this,boost::ref(f))();

boost user mail list有人建议
boost::bind(&test1::handle<boost::_bi::protected_bind_t<F>
>,this, protect(f))();
不过我认为用户还是别去接触boost::_bi空间来的好


另一件事是:bind返回的对象支持多于它本该支持的参数.同样上面的例子,改为
boost::bind(&test1::handle<F>,this,boost::ref(f))(1,2,3,4,5);
照样编译通过.带来的好处就是像boost::asio这样的库接受的回调可以很灵活,你要不要boost::system::error_code,bytes_transferred都没问题.asio::io_service总是压入所有必须的参数来进行回调,而被bind后的回调对象会只抽取自己必须的参数.

posted @ 2011-03-16 12:56 FireEmissary 阅读(3042) | 评论 (0)编辑 收藏

     摘要: KMP 算法并非优化 用于实际的字符串查找并不理想.要费劲心血实现和优化它,才能在特定的字符串上略微超过(也可能略微逊过)std::search.
  阅读全文
posted @ 2010-07-01 21:34 FireEmissary 阅读(3941) | 评论 (2)编辑 收藏

3.0以后的opengl引入了废弃模式和profile定义.其中core profile上下文不支持被废弃的函数.
freeglut支持兼容模式指定:
glutInitContextVersion指定版本
glutInitContextFlags指定是否向后兼容.
glutInitContextProfile指定profile是否core的.

freeglut自带的例子smooth_opengl3把glutInitContextVersion指定参数GLUT_FORWARD_COMPATIBLE,windows平台映射到wgl的WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB标记.而WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB标记的意思是"向前"兼容,也就是说不支持废弃的函数.
这样smooth_opengl3编译出来的例子出现gl错误,什么显示都没有.

解决方案是注释掉glutInitContextFlags调用,因为默认上下文就是以兼容模式建立.
glutInitContextProfile请求opengl 3.2以上版本才有效果,通常可以不管它.
posted @ 2010-06-20 18:21 FireEmissary 阅读(1523) | 评论 (0)编辑 收藏

 

经典的求公共子序列算法需要两个序列的长度已知.而且通常用于计算字符串的公共子序列.

我实现的算法针对原有的算法输入需求解耦合,使得算法极度可适配.能用于字符串公共子序列计算和文件diff计算.理论上能用于任何具备相似特征的两个序列的公共子序列计算.

LCS_Calculate有三个变种:

 

template<typename L_Iterator,typename R_Iterator,typename Container>

LCS_Size FEtool::LCS_Calculate(L_Iterator lbeg,L_Iterator lend,  R_Iterator rbeg,R_Iterator rend,Container 
&out);

template
<typename L_Iterator,typename R_Container,typename Container>

inline LCS_Size FEtool::LCS_Calculate(L_Iterator lbeg,L_Iterator lend,  R_Container 
const&rcontainer, Container &out);

template
<typename L_Container,typename R_Container,typename Container>

inline LCS_Size FEtool::LCS_Calculate(L_Container 
const& lcontainer,   R_Container const&rcontainer, Container &out);

L_Iterator接受输入迭代器. R_Iterator接受随机迭代器. L_ContainerR_Container分别调用它们的begin()end()方法转调用到LCS_Calculate的第一个版本.

L_*打头的指代比较序列中左边那个,R_*打头的指代比较序列中右边那个.

最后一个参数Container&out接收一个容器用来输出序列各段相同的地方.典型的Container参数为std::deque<FEtool::SectionCommon> section;也可以为FEtool:: EmptyContainer.

class EmptyContainer
{
public:
    
void push_back(SectionCommon const&){};
    LCS_Size size()
{return 0;}
    
void clear(){}
}
;


如果为FEtool:: EmptyContainer参数则通过模板特化代码选择不计算两段序列的相同部分。

 

struct LCS_Compare_Trait
{
template
<typename L,typename R>
static   bool equal(L const& left, R const& right)
        
{
            
return left==right;
        }

}
;

定义了比较算法,默认用operator==.你可以在FEtool空间通过特化或偏特化LCS_Compare_Trait:: equal来定制它.

 

struct SectionCommon
{
    LCS_Size L_begin;
    LCS_Size R_begin;
    LCS_Size count;
    
void clear(){L_begin=0;R_begin=0;count=0;}
}
;

指示两个序列的相同部分. 比如SectionCommon:: L_begin0, SectionCommon:: R_begin10, SectionCommon::count5.就表示左边序列从0开始的5个数据,和右边序列从10开始的5个数据都相同.

 

LCS_Calculate内部根据传入参数优化实现.经过对经典的动态规划解公共子序列算法的考察发现,外围那个循环只需要遍历它代表的序列一次;即左边序列则满足输入迭代器即可.它要求右边序列始终是传入随机迭代器.内部计算用到的数组使用了滚动数组(LCSArray)实现,空间占用为右边序列长度*2.


LCS_Calculate
的最后一个参数不为EmptyContainer则会计算公共子序列在左右序列中各段的顺序和长度.这里L_Iterator是不是随机访问迭代器就会影响到性能了.L_Iterator不是随机迭代器内部就会用到一个动态增长的辅助数组(TrackArrayDynamic)来做回溯; L_Iterator是随机迭代器则直接一次申请(左序列*右序列)这么大的空间(TrackArrayStatic)来辅助回溯计算.
而如果LCS_Calculate的最后一个参数为EmptyContainer则会选择一个空数组(TrackArrayEmpty)实现.TrackArrayEmpty类把所有操作展开为空操作.

所有这些,基于模板来自动选择.用户不需要指定不同的函数来优化性能:

template<typename L_Iterator,typename R_Iterator,typename Container/*vector<LCS_Section>*/>
LCS_Size LCS_Calculate(L_Iterator lbeg,L_Iterator lend,
                    R_Iterator rbeg,R_Iterator rend,
                    Container 
&out)
{
    
out.clear();
    detail::LCSArray array(rend
-rbeg);
   typedef detail::SelectTrackArray
<Container,typename std::iterator_traits<L_Iterator>::iterator_category> SelectTrack;//选择适当的回溯数组
   typename SelectTrack::Array trackArr(SelectTrack::TotalRows(lbeg,lend),array.columns());//选择适当的回溯数组
    LCS_Size leftSize;
    LCS_Size rightSize;
  
for( leftSize=1;lbeg!=lend;++lbeg,++leftSize)//外层只需要是输入迭代器就可
        
for( rightSize=1;rightSize<=array.columns();++rightSize)
        
{
            
if(LCS_Compare_Trait::equal(*lbeg,*(rbeg+rightSize-1))){
                array(leftSize,rightSize)
=array(leftSize-1,rightSize-1)+1;
                trackArr(leftSize,rightSize)
=0;
            }

            
else if(array(leftSize-1,rightSize)>=array(leftSize,rightSize-1)){
                array(leftSize,rightSize)
=array(leftSize-1,rightSize);
                trackArr(leftSize,rightSize)
=1;
            }

            
else{
                array(leftSize,rightSize)
=array(leftSize,rightSize-1);
                trackArr(leftSize,rightSize)
=-1;
            }


        }

        detail::LCS_KeepTrack(trackArr,
out);

    
return array(leftSize-1,array.columns());

}


完整代码包括测试代码下载

posted @ 2010-03-27 19:31 FireEmissary 阅读(2802) | 评论 (1)编辑 收藏

仅列出标题
共2页: 1 2