How do I remove code duplication between similar const and non-const member functions?

后端 未结 19 1731
天涯浪人
天涯浪人 2020-11-22 00:30

Let\'s say I have the following class X where I want to return access to an internal member:

class Z
{
    // details
};

class X
{
    std::vec         


        
19条回答
  •  梦毁少年i
    2020-11-22 01:07

    I came up with a macro that generates pairs of const/non-const functions automatically.

    class A
    {
        int x;    
      public:
        MAYBE_CONST(
            CV int &GetX() CV {return x;}
            CV int &GetY() CV {return y;}
        )
    
        //   Equivalent to:
        // int &GetX() {return x;}
        // int &GetY() {return y;}
        // const int &GetX() const {return x;}
        // const int &GetY() const {return y;}
    };
    

    See the end of the answer for the implementation.

    The argument of MAYBE_CONST is duplicated. In the first copy, CV is replaced with nothing; and in the second copy it's replaced with const.

    There's no limit on how many times CV can appear in the macro argument.

    There's a slight inconvenience though. If CV appears inside of parentheses, this pair of parentheses must be prefixed with CV_IN:

    // Doesn't work
    MAYBE_CONST( CV int &foo(CV int &); )
    
    // Works, expands to
    //         int &foo(      int &);
    //   const int &foo(const int &);
    MAYBE_CONST( CV int &foo CV_IN(CV int &); )
    

    Implementation:

    #define MAYBE_CONST(...) IMPL_CV_maybe_const( (IMPL_CV_null,__VA_ARGS__)() )
    #define CV )(IMPL_CV_identity,
    #define CV_IN(...) )(IMPL_CV_p_open,)(IMPL_CV_null,__VA_ARGS__)(IMPL_CV_p_close,)(IMPL_CV_null,
    
    #define IMPL_CV_null(...)
    #define IMPL_CV_identity(...) __VA_ARGS__
    #define IMPL_CV_p_open(...) (
    #define IMPL_CV_p_close(...) )
    
    #define IMPL_CV_maybe_const(seq) IMPL_CV_a seq IMPL_CV_const_a seq
    
    #define IMPL_CV_body(cv, m, ...) m(cv) __VA_ARGS__
    
    #define IMPL_CV_a(...) __VA_OPT__(IMPL_CV_body(,__VA_ARGS__) IMPL_CV_b)
    #define IMPL_CV_b(...) __VA_OPT__(IMPL_CV_body(,__VA_ARGS__) IMPL_CV_a)
    
    #define IMPL_CV_const_a(...) __VA_OPT__(IMPL_CV_body(const,__VA_ARGS__) IMPL_CV_const_b)
    #define IMPL_CV_const_b(...) __VA_OPT__(IMPL_CV_body(const,__VA_ARGS__) IMPL_CV_const_a)
    

    Pre-C++20 implementation that doesn't support CV_IN:

    #define MAYBE_CONST(...) IMPL_MC( ((__VA_ARGS__)) )
    #define CV ))((
    
    #define IMPL_MC(seq) \
        IMPL_MC_end(IMPL_MC_a seq) \
        IMPL_MC_end(IMPL_MC_const_0 seq)
    
    #define IMPL_MC_identity(...) __VA_ARGS__
    #define IMPL_MC_end(...) IMPL_MC_end_(__VA_ARGS__)
    #define IMPL_MC_end_(...) __VA_ARGS__##_end
    
    #define IMPL_MC_a(elem) IMPL_MC_identity elem IMPL_MC_b
    #define IMPL_MC_b(elem) IMPL_MC_identity elem IMPL_MC_a
    #define IMPL_MC_a_end
    #define IMPL_MC_b_end
    
    #define IMPL_MC_const_0(elem)       IMPL_MC_identity elem IMPL_MC_const_a
    #define IMPL_MC_const_a(elem) const IMPL_MC_identity elem IMPL_MC_const_b
    #define IMPL_MC_const_b(elem) const IMPL_MC_identity elem IMPL_MC_const_a
    #define IMPL_MC_const_a_end
    #define IMPL_MC_const_b_end
    

提交回复
热议问题