user1180790
user1180790

Reputation:

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

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

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.

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

No goals

Note

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

Upvotes: 1

Views: 182

Answers (2)

R Sahu
R Sahu

Reputation: 206567

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.

Upvotes: 6

NathanOliver
NathanOliver

Reputation: 180500

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

Upvotes: 3

Related Questions