模板常量/非常量方法

template const / non const method

假设我们有这样的代码:

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();
}

在这两种情况下,INIFile<>::process() 将是一个非 const 成员函数。

如果 CALLBACK::operator()const,是否有一种简单的方法使 process() 成为 const 成员函数,而无需重复 INIFile<>::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;
};

您的问题已通过执行以下操作得到解决:

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;
};

这当然在技术上超载了 process,但它具有您想要的完全相同的效果。如果 processor 的调用运算符 标记为 const,并且您尝试通过对象的 const 引用或 const 副本调用 process,您会得到编译错误(与您的解决方案不同)。那是因为 processconst 重载被调用,它将 const 添加到传递的处理器,然后处理器上的调用运算符当然会失败。

但是,如果回调确实提供了一个 const 调用运算符,那么任何一个进程调用都会做完全相同的事情。这实际上意味着您可以在 INIFile 的 const 副本上调用 process,这相当于 processconst.

如果回调还重载调用运算符,则此实现将转发到正确的那个,但您没有将其指定为条件。唯一需要注意的是,process_impl 永远不应该访问成员变量 processor,因为该成员变量将始终是可变的,即即使不应该调用也会工作(如你的解决方案)。我故意遮挡以防止这种情况发生。这不是那么漂亮,但作为一个实现细节,它还不错,而且它确实删除了重复。