Как инициализировать несколько постоянных переменных-членов, которые разделяют сложный код инициализации? - PullRequest
1 голос
/ 27 марта 2019

Введение

Давайте представим этот простой пример:

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

Викторины

  • Введенный класс имеет две переменные-члены: A и B.
  • Они принимают значения A ^ B + A и A ^ B + B соответственно.
  • Оба они имеют общий комплексный код инициализации (допустим, std::pow сложный).

Задача

Я бы хотел, чтобы члены A и B const.

Вопрос

Как это сделать, не повторяя сложную инициализацию( т.е. избегать вызова std::pow дважды)?

Что я пробовал

#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. Создать struct Init, который принимает роль предыдущей версиикласс X.
  2. Создание X членов const при сохранении Init членов не const.
  3. Использование делегирования конструктора для перенаправления аргументов конструктора в Init.
  4. Переместите не const переменные-члены из Init в X и сделайте их const.
    • Обратите внимание, что std::move нет int равно TriviallyCopyable .

Однако, мойРешение кажется слишком сложным.Мы будем благодарны за любую помощь.

Нет целей

  • Создайте еще одну X переменную-член, которая будет хранить общий результат кода ( т.е. std::pow).
  • Добавьте еще один уровень косвенности вне класса X ( например, введите базовый класс для X).

Примечание

Решения могутиспользуйте более новые версии C ++, чем C ++ 11.

Ответы [ 2 ]

5 голосов
/ 27 марта 2019

Использование делегирующего конструктора - хороший вариант для таких случаев.

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

Логика / вычисления в func1, func2 и func3 могут быть настолько простыми или сложными, насколько вам нужно.

3 голосов
/ 27 марта 2019

Вы можете решить эту проблему с помощью заводской функции.Вы делаете конструктор X закрытым, а затем используете функцию друга / статические функции для получения объектов X.Затем вы можете сделать сложный код в теле функции и затем передать эти значения конструктору X. Это будет выглядеть примерно как

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

и будет использоваться как

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