How to initialize multiple constant member variables that shares complex initialization code?

孤人 提交于 2019-12-24 14:13:53

问题


Introduction

Let's introduce this simple example:

#include <cmath>

class X
{
public: // Members

    /// A ^ B + A
    int A;

    /// A ^ B + B
    int B;

public: // Specials

    X(
        const int & A,
        const int & B
    )
        : A(A)
        , B(B)
    {
        const auto Pow = static_cast<int>(std::pow(A, B));

        this->A += Pow;
        this->B += Pow;
    }
};

Trivia

  • Introduced class has two member variables: A and B.
  • They take value of A ^ B + A and A ^ B + B, respectively.
  • Both of them shares common complex initialization code (let's assume std::pow is complex).

Problem

I'd like to make both A and B members const.

Question

How to do that without repeating complex initialization (ie avoid calling std::pow twice)?

What I've tried

#include <cmath>

class X
{
public: // Members

    /// A ^ B + A
    const int A;

    /// A ^ B + B
    const int B;

public: // Helpers

    struct Init
    {
    public: // Members

        int A;
        int B;

    public: // Specials

        Init(
            const int & A,
            const int & B
        )
            : A(A)
            , B(B)
        {
            const auto Pow = static_cast<int>(std::pow(A, B));

            this->A += Pow;
            this->B += Pow;
        }
    };

public: // Specials

    X(
        const Init& Init
    )
        : A(Init.A)
        , B(Init.B)
    {};

    X(
        const int & A,
        const int & B
    )
        : X(Init(
            A,
            B
        ))
    {};
};
  1. Create struct Init that takes role of past version of class X.
  2. Make X members const while keep Init members non const.
  3. Use constructor delegation to redirect constructor arguments to Init.
  4. Move non const member variables from Init to X and make them const.
    • Note there is no std::move as int is TriviallyCopyable.

However, my solution seems overcomplicated. Any help would be appreciated.

No goals

  • Make another X member variable that will store common code result (ie std::pow).
  • Add another level of indirection outside X class (eg introduce base class for X).

Note

Solutions can use newer versions of C++ than C++11.


回答1:


Using a delegating constructor is a good option for such cases.

class X
{
   public: // Members

      /// A ^ B + A
      const int A;

      /// A ^ B + B
      const int B;

   public:

      X(int a, int b) : X(a, b, func1(a, b)) {}

   private:

      X(int a, int b, int c) : A(func2(a, b, c)), B(func3(a, b, c)) {}

      static int func1(int a, int b) { return std::pow(a,b); }
      static int func2(int a, int b, int c) { return (a + c); }
      static int func3(int a, int b, int c) { return (b + c); }
};

The logic/computation in func1, func2, and func3 can be as simple or as complex as you need.




回答2:


You can solve this by using a factory function. You make the constructor of X private and then use a friend/static function to get objects of X. Then you can do the complex code in the body of the function and then pass those values to the constructor of X. That would look something like

class X
{
public:
    const int A;
    const int B;
    friend X make_X(int a, int b)
    {
        // do complex stuff
        return X(complex_result1, complex_result2);
    }
    // or
    static X make(int a, int b)
    {
        // do complex stuff
        return X(complex_result1, complex_result2);
    }
private:
    X(const int  A, const int  B) : A(A), B(B) {}
};

and would be used like

X foo = make_x(a, b);
//or
X foo = X::make(a, b);


来源:https://stackoverflow.com/questions/55382549/how-to-initialize-multiple-constant-member-variables-that-shares-complex-initial

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!