C++ 模板常量/非常量方法
假设我们有这样的代码:C++ 模板常量/非常量方法,c++,c++11,templates,code-duplication,C++,C++11,Templates,Code Duplication,假设我们有这样的代码: template<class CALLBACK> struct INIFile{ INIFile(CALLBACK &processor) : processor(processor ){} bool process(){ // lots of code here, // call processor processor(123);
template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(processor ){}
bool process(){
// lots of code here,
// call processor
processor(123);
return true;
}
CALLBACK &processor;
};
struct MyProcessor{
void operator()(int val){
// do something
}
};
struct MyConstProcessor{
void operator()(int val) const{ // !!!!!
// do something
}
};
int main(){
MyProcessor p;
INIFile<MyProcessor> ini(p);
ini.process();
// const case:
MyConstProcessor cp;
INIFile<MyConstProcessor> cini(cp);
cini.process();
}
模板
结构文件{
INI文件(回调和处理器):
处理器(处理器){}
布尔过程(){
//这里有很多代码,
//呼叫处理机
处理器(123);
返回true;
}
回调与处理器;
};
结构MyProcessor{
void运算符()(int val){
//做点什么
}
};
结构处理器{
void运算符()(int val)常量{//!!!!!
//做点什么
}
};
int main(){
myp;
ini文件ini(p);
ini.process();
//康斯特案件:
myconstcp;
INI文件(cp);
过程();
}
在这两种情况下,INIFile::process()
都将是非const
成员函数
如果
CALLBACK::operator()
是const
,那么有没有一种简单的方法可以使process()
成为const
成员函数,而不必重复ini文件::process()
中的所有逻辑?我发现的另一种方法,但我不太喜欢它是使用指针而不是引用
这是代码
注意:在这种特殊情况下,我们根本不需要检查nullptr
template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(& processor ){}
bool process() const{
// lots of code here,
// call processor
processor->operator()(123);
return true;
}
CALLBACK *processor;
};
模板
结构文件{
INI文件(回调和处理器):
处理器(&处理器){}
bool进程()常量{
//这里有很多代码,
//呼叫处理机
处理器->运算符()(123);
返回true;
}
回调*处理器;
};
您的问题可以通过执行以下操作来解决:
template<class CALLBACK>
struct INIFile{
INIFile(CALLBACK &processor) :
processor(processor){}
template <class T>
bool process_impl(T& processor) const {
// deliberately shadow processor
// reduce likelihood of using member processor, but can use other member variables
// lots of code
processor(123);
return true;
}
bool process() const {
return process_impl(const_cast<const CALLBACK&>(processor));
}
bool process() {
return process_impl(processor);
}
CALLBACK& processor;
};
模板
结构文件{
INI文件(回调和处理器):
处理器(处理器){}
模板
布尔进程执行(T和处理器)常量{
//阴影处理器
//减少使用成员处理器的可能性,但可以使用其他成员变量
//很多代码
处理器(123);
返回true;
}
bool进程()常量{
返回进程执行(常量转换(处理器));
}
布尔过程(){
返回处理程序(处理器);
}
回调与处理器;
};
从技术上讲,这当然会使过程过载,但它的效果与您想要的完全相同。如果处理器
的调用运算符未标记为const,并且您试图通过对象的const引用或const副本调用进程
,则会出现编译错误(与解决方案不同)。这是因为调用了process
的const
重载,它将const
添加到传递的处理器中,然后处理器上的call操作符当然会失败
但是,如果回调确实提供了一个const
call操作符,那么两个进程调用都将执行完全相同的操作。这实际上意味着您可以在INIFile
的常量副本上调用process
,这相当于process
是const
如果回调还重载了call操作符,那么这个实现将转发到正确的位置,但您没有将其指定为条件。唯一需要注意的是,process\u impl
不应该访问成员变量processor
,因为该成员变量始终是可变的,即调用即使在不应该的时候也会工作(就像在您的解决方案中一样)。我有意阻止这种情况。这并不漂亮,但作为一个实现细节,它并没有那么糟糕,它确实消除了重复。与noexcept
相反,没有const(condition)
限定符。@NathanOliver:OP希望有InFile::process()
和InFile::process()const
无需重复代码。@Jarod42正是我的观点。但是有什么窍门吗?我有一些想法,比如将“这里有很多代码”提取到const函数中,但它有几个分支,结果非重复代码太复杂了。可以因此,如果CALLBACK::operator()
恰好是const
,那么您希望process()
是const
@NathanOliver。尽管如此,请随意编辑此解决方案中的问题,进程
始终为常量,而不管回调::运算符()
是否为常量。有一个真正的解决方案,非常简单,我很快就会发布。很好的解决方案,但是有没有理由使用const\u cast
而不是static\u cast
??它不就是回调&
->常量回调&
。或者只是少打一个字母:)我想在这种情况下没有真正的理由,因为很难想象你会在任何一种情况下犯错误;很明显,你在添加常量,你必须努力工作才能得到错误的类型。sfinae的惊人用法