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的惊人用法