问题
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
andB
. - They take value of
A ^ B + A
andA ^ 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
))
{};
};
- Create
struct Init
that takes role of past version of classX
. - Make
X
membersconst
while keepInit
members nonconst
. - Use constructor delegation to redirect constructor arguments to
Init
. - Move non
const
member variables fromInit
toX
and make themconst
.- Note there is no
std::move
asint
is TriviallyCopyable.
- Note there is no
However, my solution seems overcomplicated. Any help would be appreciated.
No goals
- Make another
X
member variable that will store common code result (iestd::pow
). - Add another level of indirection outside
X
class (eg introduce base class forX
).
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