C++ template to cover const and non-const method

后端 未结 7 1482
北荒
北荒 2020-12-29 22:48

I have a problem with duplication of identical code for const and non-const versions. I can illustrate the problem with some code. Here are two s

7条回答
  •  执笔经年
    2020-12-29 23:18

    Since your ultimate implementations are not always identical, I don't think there's a real solution for your perceived "problem".

    Let's think about this. We have to cater for the situations where Aggregate is either const or non-const. Surely we should not relax that (e.g. by providing only a non-const version).

    Now, the const-version of the operator can only call visitors which take their argument by const-ref (or by value), while the non-constant version can call any visitor.

    You might think that you can replace one of the two implementations by the other. To do so, you would always implement the const version in terms of the non-const one, never the other way around. Hypothetically:

    void operator()(Visitor & v) { /* #1, real work */ }
    
    void operator()(Visitor & v) const
    {
      const_cast(this)->operator()(v);  // #2, delegate
    }
    

    But for this to make sense, line #2 requires that the operation is logically non-mutating. This is possible for example in the typical member-access operator, where you provide either a constant or a non-constant reference to some element. But in your situation, you cannot guarantee that the operator()(v) call is non-mutating on *this!

    Therefore, your two functions are really rather different, even though they look formally similar. You cannot express one in terms of the other.

    Maybe you can see this another way: Your two functions aren't actually the same. In pseudo-code, they are:

    void operator()(Visitor & v) {
      v( (Aggregate *)->i );
      v( (Aggregate *)->d );
    }
    
    void operator()(Visitor & v) const {
      v( (const Aggregate *)->i );
      v( (const Aggregate *)->d );
    }
    

    Actually, coming to think of it, perhaps if you're willing to modify the signature a bit, something can be done:

    template 
    void visit(Visitor & v)
    {
      typedef typename std::conditional::type this_p;
      v(const_cast(this)->i);
      v(const_cast(this)->d);
    }
    
    void operator()(Visitor & v) { visit<>(v); }
    void operator()(Visitor & v) const { const_cast(this)->visit()(v); }
    

提交回复
热议问题